From dc2dee0c0b44b3ae34c98d60ec722ca3ffeb05d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Mon, 2 Feb 2026 09:54:31 +0900 Subject: [PATCH] chore:api docs update --- storage/api-docs/api-docs-v1.json | 91858 +++++++++++++++++++++++++++- 1 file changed, 91418 insertions(+), 440 deletions(-) diff --git a/storage/api-docs/api-docs-v1.json b/storage/api-docs/api-docs-v1.json index 6d81faf..3750ac9 100755 --- a/storage/api-docs/api-docs-v1.json +++ b/storage/api-docs/api-docs-v1.json @@ -10,24 +10,6828 @@ }, "servers": [ { - "url": "https://api.5130.co.kr", + "url": "https://api.sam.kr/", "description": "SAM관리시스템 API 서버" } ], "paths": { - "/api/v1/debug-apikey": { - "get": { + "/api/v1/account/withdraw": { + "post": { "tags": [ - "API Key 인증" + "Account" ], - "summary": "API Key 인증 확인", - "operationId": "8d05f26a859e82207ba533ab88682ddf", + "summary": "회원 탈퇴", + "description": "SAM 회원 탈퇴 (모든 테넌트에서 탈퇴, 계정 삭제)", + "operationId": "withdrawAccount", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WithdrawRequest" + } + } + } + }, "responses": { "200": { - "description": "API Key 인증 성공" + "description": "탈퇴 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "회원 탈퇴가 완료되었습니다." + }, + "data": { + "$ref": "#/components/schemas/WithdrawResponse" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "비밀번호 불일치" }, "401": { "description": "인증 실패" + }, + "404": { + "description": "사용자를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/account/suspend": { + "post": { + "tags": [ + "Account" + ], + "summary": "사용 중지", + "description": "현재 테넌트에서만 탈퇴 (다른 테넌트 멤버십 유지)", + "operationId": "suspendAccount", + "responses": { + "200": { + "description": "사용 중지 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "사용 중지가 완료되었습니다." + }, + "data": { + "$ref": "#/components/schemas/SuspendResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "404": { + "description": "테넌트 멤버십을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/account/agreements": { + "get": { + "tags": [ + "Account" + ], + "summary": "약관 동의 정보 조회", + "description": "현재 사용자의 약관 동의 정보를 조회합니다.", + "operationId": "getAgreements", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "$ref": "#/components/schemas/AgreementsResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "404": { + "description": "사용자를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Account" + ], + "summary": "약관 동의 정보 수정", + "description": "약관 동의 정보를 수정합니다.", + "operationId": "updateAgreements", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAgreementsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "수정 성공" + }, + "data": { + "properties": { + "agreements": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/AgreementItem" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "404": { + "description": "사용자를 찾을 수 없음" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/users": { + "get": { + "tags": [ + "Admin-Users" + ], + "summary": "사용자 목록", + "description": "필터/검색/페이지네이션으로 사용자 목록을 조회합니다.", + "operationId": "1b7ae16b7a3e0031934d842f83155133", + "parameters": [ + { + "name": "q", + "in": "query", + "description": "이름/이메일 검색어", + "schema": { + "type": "string" + } + }, + { + "name": "tenant_id", + "in": "query", + "description": "특정 테넌트로 필터", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "role", + "in": "query", + "description": "역할 코드", + "schema": { + "type": "string", + "example": "manager" + } + }, + { + "name": "is_active", + "in": "query", + "description": "활성여부", + "schema": { + "type": "boolean", + "example": 1 + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/admin/users?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/admin/users?page=3" + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/admin/users?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/admin/users" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Admin-Users" + ], + "summary": "사용자 생성", + "description": "새 사용자를 생성합니다. (초기 비밀번호/역할 포함 가능)", + "operationId": "63469d8cf97c626b541f2c171ed516ad", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "name", + "email", + "password" + ], + "properties": { + "user_id": { + "type": "string", + "example": "test001" + }, + "name": { + "type": "string", + "example": "김관리" + }, + "email": { + "type": "string", + "example": "admin@kdcorp.co.kr" + }, + "password": { + "type": "string", + "example": "Init!2345" + }, + "phone": { + "type": "string", + "example": "010-3333-4444" + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "manager" + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "생성됨", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/User" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "이메일 중복", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/users/{id}": { + "get": { + "tags": [ + "Admin-Users" + ], + "summary": "사용자 단건 조회", + "description": "ID 기준 사용자 상세", + "operationId": "82122febae83557b8327464f8223f085", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 101 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Admin-Users" + ], + "summary": "사용자 수정", + "description": "이름/연락처/역할/활성여부 등 변경", + "operationId": "6558323c5811b3b7c97fd7b20cf8e4f6", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "name": { + "type": "string", + "example": "김관리" + }, + "phone": { + "type": "string", + "example": "010-3333-4444" + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "manager", + "staff" + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Admin-Users" + ], + "summary": "사용자 삭제(소프트 삭제)", + "description": "deleted_at / deleted_by 기록", + "operationId": "559b8bf227a1156fcd1ef4656fa7c6df", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "삭제성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "변경 성공" + }, + "data": { + "type": "string", + "example": "Success" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/users/{id}/status": { + "patch": { + "tags": [ + "Admin-Users" + ], + "summary": "활성/비활성 전환", + "description": "지정된 사용자의 is_active 상태를 변경합니다.", + "operationId": "7da65b864daadca1481fa87d0f99930d", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "사용자 고유 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "변경 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "테넌트 사용자 활성/비활성 성공" + }, + "data": { + "properties": { + "is_active": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/users/{id}/restore": { + "post": { + "tags": [ + "Admin-Users" + ], + "summary": "삭제 복구", + "description": "소프트 삭제 복구", + "operationId": "78f17d71e4bbd8c78cf51f267fa8f254", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "변경 성공" + }, + "data": { + "type": "string", + "example": "Success" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/users/{id}/roles": { + "post": { + "tags": [ + "Admin-Users" + ], + "summary": "역할 부여", + "description": "사용자에게 역할 추가", + "operationId": "be504b509f9d3a4daae50007ddef915f", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "roles" + ], + "properties": { + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "manager" + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "204": { + "description": "부여 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "변경 성공" + }, + "data": { + "type": "object", + "example": null, + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "이메일/역할 중복 등 충돌", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/users/{id}/roles/{role}": { + "delete": { + "tags": [ + "Admin-Users" + ], + "summary": "역할 해제", + "description": "사용자에서 특정 역할 제거", + "operationId": "4d9980bcd4442c9e8f175083a15d4f62", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "role", + "in": "path", + "required": true, + "schema": { + "type": "string", + "example": "manager" + } + } + ], + "responses": { + "204": { + "description": "부여 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "변경 성공" + }, + "data": { + "type": "object", + "example": null, + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "요청 충돌(없는 역할/이미 제거됨 등)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/users/{id}/reset-password": { + "post": { + "tags": [ + "Admin-Users" + ], + "summary": "비밀번호 초기화", + "description": "지정된 사용자의 비밀번호를 새 임시 비밀번호로 초기화합니다.\n * - 관리자 권한 확인은 미들웨어/가드에서 처리됩니다.\n * - 기본적으로 응답에 비밀번호를 노출하지 않으며, return_password=1일 때만 임시 비밀번호를 반환합니다(운영 환경에서는 노출 비권장).", + "operationId": "bb7097f56a0ea290614a78e9e32c7701", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "사용자 고유 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "new_password": { + "description": "지정 시 해당 값으로 비밀번호 초기화, 미지정 시 서버에서 랜덤 생성", + "type": "string", + "maxLength": 64, + "minLength": 8, + "example": "Temp!1234" + }, + "return_password": { + "description": "1이면 응답에 임시 비밀번호 포함(개발/테스트용)", + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 0 + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "초기화 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "테넌트 사용자 비밀번호 초기화 성공" + }, + "data": { + "properties": { + "status": { + "type": "string", + "example": "ok" + }, + "temp_password": { + "description": "return_password=1일 때만 포함", + "type": "string", + "example": "Temp!1234", + "nullable": true + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "요청 충돌(정책 위반 등)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/fcm/send": { + "post": { + "tags": [ + "Admin FCM" + ], + "summary": "FCM 푸시 발송", + "description": "대상 토큰에 FCM 푸시 알림을 발송합니다. 테넌트, 사용자, 플랫폼으로 대상을 필터링할 수 있습니다.", + "operationId": "f0759f964bd727c1b2f1e746389355a4", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminFcmSendRequest" + } + } + } + }, + "responses": { + "200": { + "description": "발송 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "FCM 발송이 완료되었습니다." + }, + "data": { + "properties": { + "log_id": { + "type": "integer", + "example": 1 + }, + "total_tokens": { + "type": "integer", + "example": 150 + }, + "success_count": { + "type": "integer", + "example": 148 + }, + "failure_count": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "발송 대상 없음 또는 검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/admin/fcm/preview-count": { + "get": { + "tags": [ + "Admin FCM" + ], + "summary": "대상 토큰 수 미리보기", + "description": "발송 전 필터 조건에 맞는 활성 토큰 수를 미리 확인합니다.", + "operationId": "3724082eabdb919d96390015598b51cd", + "parameters": [ + { + "name": "tenant_id", + "in": "query", + "description": "테넌트 ID", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "user_id", + "in": "query", + "description": "사용자 ID", + "required": false, + "schema": { + "type": "integer", + "example": 5 + } + }, + { + "name": "platform", + "in": "query", + "description": "플랫폼", + "required": false, + "schema": { + "type": "string", + "enum": [ + "ios", + "android", + "web" + ], + "example": "android" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "count": { + "type": "integer", + "example": 150 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/admin/fcm/tokens": { + "get": { + "tags": [ + "Admin FCM" + ], + "summary": "토큰 목록 조회", + "description": "등록된 FCM 토큰 목록을 조회합니다. 테넌트, 플랫폼, 활성 상태, 에러 여부로 필터링할 수 있습니다.", + "operationId": "db14af6ba3f650ce53270f4bfb1b58d7", + "parameters": [ + { + "name": "tenant_id", + "in": "query", + "description": "테넌트 ID", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "platform", + "in": "query", + "description": "플랫폼", + "required": false, + "schema": { + "type": "string", + "enum": [ + "ios", + "android", + "web" + ], + "example": "android" + } + }, + { + "name": "is_active", + "in": "query", + "description": "활성 상태", + "required": false, + "schema": { + "type": "boolean", + "example": true + } + }, + { + "name": "has_error", + "in": "query", + "description": "에러 여부", + "required": false, + "schema": { + "type": "boolean", + "example": false + } + }, + { + "name": "search", + "in": "query", + "description": "사용자명/이메일 검색", + "required": false, + "schema": { + "type": "string", + "example": "홍길동" + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "example": 20 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/AdminFcmTokenPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/admin/fcm/tokens/stats": { + "get": { + "tags": [ + "Admin FCM" + ], + "summary": "토큰 통계 조회", + "description": "FCM 토큰의 전체 통계를 조회합니다. 활성/비활성, 플랫폼별 분포 등을 확인할 수 있습니다.", + "operationId": "fc36a5678a785d91af87719536d1419c", + "parameters": [ + { + "name": "tenant_id", + "in": "query", + "description": "테넌트 ID (미지정시 전체)", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/AdminFcmTokenStats" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/admin/fcm/tokens/{id}/toggle": { + "patch": { + "tags": [ + "Admin FCM" + ], + "summary": "토큰 상태 토글", + "description": "토큰의 활성/비활성 상태를 토글합니다.", + "operationId": "1a147917823fe6b72d98d65558735f6f", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "토큰 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "상태 변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "토큰 상태가 변경되었습니다." + }, + "data": { + "$ref": "#/components/schemas/AdminFcmToken" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "토큰을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/admin/fcm/tokens/{id}": { + "delete": { + "tags": [ + "Admin FCM" + ], + "summary": "토큰 삭제", + "description": "FCM 토큰을 삭제합니다.", + "operationId": "28c7d025e844f6be52e9575843c061c8", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "토큰 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "삭제되었습니다." + }, + "data": { + "properties": { + "deleted": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "토큰을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/admin/fcm/history": { + "get": { + "tags": [ + "Admin FCM" + ], + "summary": "발송 이력 조회", + "description": "FCM 발송 이력을 조회합니다. 테넌트, 상태, 기간으로 필터링할 수 있습니다.", + "operationId": "5e955cb82647df9e4f4ee18aa2cf169f", + "parameters": [ + { + "name": "tenant_id", + "in": "query", + "description": "테넌트 ID", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "status", + "in": "query", + "description": "발송 상태", + "required": false, + "schema": { + "type": "string", + "enum": [ + "pending", + "sending", + "completed", + "failed" + ], + "example": "completed" + } + }, + { + "name": "from", + "in": "query", + "description": "시작일", + "required": false, + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-01" + } + }, + { + "name": "to", + "in": "query", + "description": "종료일", + "required": false, + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "example": 20 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/AdminFcmHistoryPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/admin/global-menus": { + "get": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "글로벌 메뉴 목록 조회", + "description": "시스템 전체 글로벌 메뉴 목록을 조회합니다.", + "operationId": "e25817f47e8f320d8c47cdea759647b5", + "responses": { + "200": { + "description": "글로벌 메뉴 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "글로벌 메뉴 목록 조회" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GlobalMenu" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "글로벌 메뉴 생성", + "operationId": "cc29a1c8acf5a0d1b9c8f903b43628c3", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalMenuCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "글로벌 메뉴 생성 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "글로벌 메뉴 생성" + }, + "data": { + "$ref": "#/components/schemas/GlobalMenu" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/global-menus/tree": { + "get": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "글로벌 메뉴 트리 조회", + "description": "글로벌 메뉴를 계층 구조(트리)로 조회합니다.", + "operationId": "755bb0fce941856f107f6fdb754607f0", + "responses": { + "200": { + "description": "글로벌 메뉴 트리 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "글로벌 메뉴 트리 조회" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/GlobalMenu" + }, + { + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GlobalMenu" + } + } + }, + "type": "object" + } + ] + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/global-menus/stats": { + "get": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "글로벌 메뉴 통계 조회", + "description": "글로벌 메뉴의 통계 정보를 조회합니다.", + "operationId": "8d91371a63c33040ef3361ff85c58820", + "responses": { + "200": { + "description": "글로벌 메뉴 통계 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "글로벌 메뉴 통계 조회" + }, + "data": { + "$ref": "#/components/schemas/GlobalMenuStats" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/global-menus/{id}": { + "get": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "글로벌 메뉴 단건 조회", + "operationId": "b7fd1fd8286577d42f02956a846a0086", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "글로벌 메뉴 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "글로벌 메뉴 상세 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "글로벌 메뉴 상세 조회" + }, + "data": { + "$ref": "#/components/schemas/GlobalMenu" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "메뉴 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "글로벌 메뉴 수정", + "operationId": "de037b9135e75658c792584ac756e9ec", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "글로벌 메뉴 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalMenuUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "글로벌 메뉴 수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "글로벌 메뉴 수정" + }, + "data": { + "$ref": "#/components/schemas/GlobalMenu" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "메뉴 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "글로벌 메뉴 삭제", + "operationId": "422f87290e1e8900cddfb8dca223b465", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "글로벌 메뉴 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "글로벌 메뉴 삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "글로벌 메뉴 삭제" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "메뉴 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/global-menus/reorder": { + "post": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "글로벌 메뉴 순서 변경", + "description": "글로벌 메뉴의 정렬 순서를 일괄 변경합니다.", + "operationId": "78ab72b0eb731e99abac3b36004f9ffd", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalMenuReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "글로벌 메뉴 순서 변경 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "글로벌 메뉴 순서 변경" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/admin/global-menus/{id}/sync-to-tenants": { + "post": { + "tags": [ + "Admin.GlobalMenu" + ], + "summary": "특정 글로벌 메뉴를 모든 테넌트에 동기화", + "description": "지정한 글로벌 메뉴를 모든 테넌트의 메뉴에 동기화합니다.", + "operationId": "71abfe15d8ef9cb6b69f8e6b4ebacfb6", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "글로벌 메뉴 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "테넌트 동기화 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "모든 테넌트에 메뉴 동기화" + }, + "data": { + "properties": { + "synced_count": { + "type": "integer", + "example": 5 + }, + "created_count": { + "type": "integer", + "example": 2 + }, + "updated_count": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "메뉴 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/reports/ai": { + "get": { + "tags": [ + "AI Reports" + ], + "summary": "AI 리포트 목록 조회", + "description": "AI 리포트 목록을 페이지네이션으로 조회합니다.", + "operationId": "257acc8d484c5b463d0e6a68e6670c13", + "parameters": [ + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수 (1-100, 기본값: 15)", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "example": 15 + } + }, + { + "name": "report_type", + "in": "query", + "description": "리포트 유형 필터", + "required": false, + "schema": { + "type": "string", + "enum": [ + "daily", + "weekly", + "monthly" + ], + "example": "daily" + } + }, + { + "name": "status", + "in": "query", + "description": "처리 상태 필터", + "required": false, + "schema": { + "type": "string", + "enum": [ + "pending", + "completed", + "failed" + ], + "example": "completed" + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일 필터 (YYYY-MM-DD)", + "required": false, + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일 필터 (YYYY-MM-DD, start_date 이상)", + "required": false, + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "AI 리포트 목록을 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/AiReportPagination" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + }, + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/reports/ai/generate": { + "post": { + "tags": [ + "AI Reports" + ], + "summary": "AI 리포트 생성", + "description": "Google Gemini AI를 사용하여 비즈니스 데이터 기반 리포트를 생성합니다. 지출, 매출, 매입, 입출금, 카드/계좌, 미수금 데이터를 종합 분석합니다.", + "operationId": "40709d9d306210282fb13dbf9b4591a7", + "requestBody": { + "description": "리포트 생성 요청 (모든 필드 선택적, 기본값 사용 가능)", + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiReportGenerateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "리포트 생성 완료", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "AI 리포트가 생성되었습니다." + }, + "data": { + "$ref": "#/components/schemas/AiReport" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "AI API 오류", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + }, + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/reports/ai/{id}": { + "get": { + "tags": [ + "AI Reports" + ], + "summary": "AI 리포트 상세 조회", + "description": "특정 AI 리포트의 상세 정보를 조회합니다.", + "operationId": "bc1dd916274d843a5c9a918c993a252e", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "리포트 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "AI 리포트를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/AiReport" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "리포트 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + }, + { + "ApiKeyAuth": [] + } + ] + }, + "delete": { + "tags": [ + "AI Reports" + ], + "summary": "AI 리포트 삭제", + "description": "특정 AI 리포트를 삭제합니다.", + "operationId": "2c791c322a71f7e3876f5ed3cdbcf689", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "리포트 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "AI 리포트가 삭제되었습니다." + }, + "data": { + "type": "null" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "리포트 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + }, + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/approvals/drafts": { + "get": { + "tags": [ + "Approvals" + ], + "summary": "기안함 - 내가 작성한 문서 목록", + "description": "로그인 사용자가 기안한 결재 문서 목록을 조회합니다.", + "operationId": "9a2af54c665d12e75e1e0c8af6696109", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "draft", + "pending", + "approved", + "rejected", + "cancelled" + ] + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (제목, 문서번호)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "created_at", + "submitted_at", + "completed_at", + "title" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Approval" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 15 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/drafts/summary": { + "get": { + "tags": [ + "Approvals" + ], + "summary": "기안함 현황 카드", + "description": "기안 문서의 상태별 건수를 조회합니다.", + "operationId": "4769f4bf3ffa21dfef426e1b97a79632", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ApprovalSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/inbox": { + "get": { + "tags": [ + "Approvals" + ], + "summary": "결재함 - 내가 결재할/결재한 문서", + "description": "로그인 사용자에게 결재 요청된 문서 목록을 조회합니다.", + "operationId": "c71cafbc366c35e3e265655eaaeaada6", + "parameters": [ + { + "name": "filter", + "in": "query", + "description": "필터 (requested: 결재요청, scheduled: 결재예정, completed: 결재완료, rejected: 반려)", + "schema": { + "type": "string", + "enum": [ + "requested", + "scheduled", + "completed", + "rejected" + ] + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (제목, 문서번호, 기안자)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "submitted_at", + "enum": [ + "created_at", + "submitted_at", + "title" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Approval" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/inbox/summary": { + "get": { + "tags": [ + "Approvals" + ], + "summary": "결재함 현황 카드", + "description": "결재함의 상태별 건수를 조회합니다.", + "operationId": "9fdb213827aa7971c13ab5cf921feeb5", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/InboxSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/reference": { + "get": { + "tags": [ + "Approvals" + ], + "summary": "참조함 - 참조로 받은 문서", + "description": "로그인 사용자가 참조자로 지정된 문서 목록을 조회합니다.", + "operationId": "666c4ff1e4a884e139ad8f52c9b8503c", + "parameters": [ + { + "name": "is_read", + "in": "query", + "description": "열람 여부 필터", + "schema": { + "type": "boolean" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (제목, 문서번호, 기안자)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "submitted_at", + "enum": [ + "created_at", + "submitted_at", + "title" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Approval" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 8 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/{id}": { + "get": { + "tags": [ + "Approvals" + ], + "summary": "결재 문서 상세 조회", + "operationId": "b35e33e3fad44a7f1a983071aba48919", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Approvals" + ], + "summary": "결재 문서 삭제", + "description": "임시저장 상태의 문서만 삭제할 수 있습니다.", + "operationId": "ca30f9764c336678e3e5b6500a90b36e", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제 완료" + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "삭제 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Approvals" + ], + "summary": "결재 문서 수정", + "description": "임시저장 상태의 문서만 수정할 수 있습니다.", + "operationId": "369f16464c17ce617ab054bcb86c5e15", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 또는 수정 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals": { + "post": { + "tags": [ + "Approvals" + ], + "summary": "결재 문서 생성 (임시저장)", + "operationId": "42a5d458f7774900ddb37d21c8736f44", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalStoreRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "양식을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/{id}/submit": { + "post": { + "tags": [ + "Approvals" + ], + "summary": "결재 상신", + "description": "임시저장 문서를 결재선에 상신합니다.", + "operationId": "9ab9c789e9d2937e1f7217a31e8b6e06", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalSubmitRequest" + } + } + } + }, + "responses": { + "200": { + "description": "상신 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "상신 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/{id}/approve": { + "post": { + "tags": [ + "Approvals" + ], + "summary": "결재 승인", + "description": "현재 순서의 결재자가 문서를 승인합니다.", + "operationId": "8252aa372254965115167befe8c217f4", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "comment": { + "description": "결재 의견 (선택)", + "type": "string", + "example": "승인합니다." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "승인 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "결재 불가 상태 또는 결재 순서 아님", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/{id}/reject": { + "post": { + "tags": [ + "Approvals" + ], + "summary": "결재 반려", + "description": "현재 순서의 결재자가 문서를 반려합니다. 반려 사유는 필수입니다.", + "operationId": "0d422daa9f154a2fe61e947fef2759ac", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "comment" + ], + "properties": { + "comment": { + "description": "반려 사유 (필수)", + "type": "string", + "example": "서류가 미비합니다. 재작성 바랍니다." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "반려 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "결재 불가 상태 또는 결재 순서 아님", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "반려 사유 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/{id}/cancel": { + "post": { + "tags": [ + "Approvals" + ], + "summary": "결재 회수", + "description": "기안자가 진행중인 문서를 회수합니다.", + "operationId": "8727a68d0c21e819b76f6e4c0f904b3f", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "회수 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "회수 불가 상태 또는 기안자가 아님", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/{id}/read": { + "post": { + "tags": [ + "Approvals" + ], + "summary": "열람 처리", + "description": "참조자가 문서를 열람 처리합니다.", + "operationId": "13b764797112791f3439cb4913177bb8", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "열람 처리 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "참조자가 아님", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approvals/{id}/unread": { + "post": { + "tags": [ + "Approvals" + ], + "summary": "미열람 처리", + "description": "참조자가 문서를 미열람 처리합니다.", + "operationId": "de78aa2d2c383e07f079008d20c5f7cd", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "미열람 처리 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Approval" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "참조자가 아님", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approval-forms": { + "get": { + "tags": [ + "Approval Forms" + ], + "summary": "결재 양식 목록 조회", + "description": "필터/검색/페이지네이션으로 결재 양식 목록을 조회합니다.", + "operationId": "90b11409d796c75b4ff6298c86c40559", + "parameters": [ + { + "name": "category", + "in": "query", + "description": "카테고리 필터", + "schema": { + "type": "string", + "enum": [ + "request", + "expense", + "expense_estimate" + ] + } + }, + { + "name": "is_active", + "in": "query", + "description": "활성 상태 필터", + "schema": { + "type": "boolean" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (이름, 코드)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "created_at", + "name", + "code", + "category" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApprovalForm" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Approval Forms" + ], + "summary": "결재 양식 생성", + "operationId": "30b4246af4d226295d54b07ac896924a", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalFormCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ApprovalForm" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (코드 중복 등)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approval-forms/active": { + "get": { + "tags": [ + "Approval Forms" + ], + "summary": "활성 결재 양식 목록 (셀렉트박스용)", + "description": "활성화된 결재 양식만 간략하게 조회합니다.", + "operationId": "ba5ea916fed25bee4704d0eb92d54a13", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "품의서" + }, + "code": { + "type": "string", + "example": "REQUEST_01" + }, + "category": { + "type": "string", + "example": "request" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approval-forms/{id}": { + "get": { + "tags": [ + "Approval Forms" + ], + "summary": "결재 양식 상세 조회", + "operationId": "48eb28aa92ddbc00040563678285608a", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "양식 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ApprovalForm" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "양식을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Approval Forms" + ], + "summary": "결재 양식 삭제", + "description": "사용 중인 양식은 삭제할 수 없습니다.", + "operationId": "5d2123d11fec8fe8e0d0032969a7b1a6", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "양식 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제 완료" + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "삭제 불가 (사용 중)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "양식을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Approval Forms" + ], + "summary": "결재 양식 수정", + "operationId": "c71a0f0b624b54c91a83da990f7072c1", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "양식 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalFormUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ApprovalForm" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "양식을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approval-lines": { + "get": { + "tags": [ + "Approval Lines" + ], + "summary": "결재선 목록 조회", + "operationId": "3b7502ea0b51f0fea26f939fcd5e8727", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (이름)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "created_at", + "name", + "is_default" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApprovalLine" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Approval Lines" + ], + "summary": "결재선 생성", + "operationId": "0a55ae96bebd599bff59f086e0dcf15c", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalLineCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ApprovalLine" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/approval-lines/{id}": { + "get": { + "tags": [ + "Approval Lines" + ], + "summary": "결재선 상세 조회", + "operationId": "9c22e50ede785b2ea0d81c8b344f54bf", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "결재선 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ApprovalLine" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "결재선을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Approval Lines" + ], + "summary": "결재선 삭제", + "operationId": "33d210e51585bdb3c48e0e4fefc1cdcd", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "결재선 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제 완료" + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "결재선을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Approval Lines" + ], + "summary": "결재선 수정", + "operationId": "4ed302d725a700acd289339d46930570", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "결재선 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApprovalLineUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ApprovalLine" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "결재선을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/attendances": { + "get": { + "tags": [ + "Attendances" + ], + "summary": "근태 목록 조회", + "description": "필터/검색/페이지네이션으로 근태 목록을 조회합니다.", + "operationId": "417bc75584b71cbbe422ce657a878de1", + "parameters": [ + { + "name": "user_id", + "in": "query", + "description": "사용자 ID 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "date", + "in": "query", + "description": "특정 날짜 (YYYY-MM-DD)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "date_from", + "in": "query", + "description": "시작 날짜", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "date_to", + "in": "query", + "description": "종료 날짜", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "status", + "in": "query", + "description": "근태 상태", + "schema": { + "type": "string", + "enum": [ + "onTime", + "late", + "absent", + "vacation", + "businessTrip", + "fieldWork", + "overtime", + "remote" + ] + } + }, + { + "name": "department_id", + "in": "query", + "description": "부서 ID 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "base_date", + "enum": [ + "base_date", + "status", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Attendance" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 100 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Attendances" + ], + "summary": "근태 등록 (Upsert)", + "description": "근태 기록을 등록합니다. 같은 날 같은 사용자의 기록이 있으면 업데이트, 없으면 새로 생성합니다.", + "operationId": "4f91cb0920afef1c60dfe882abcb6bb0", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AttendanceCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "등록/수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Attendance" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/attendances/monthly-stats": { + "get": { + "tags": [ + "Attendances" + ], + "summary": "월간 통계 조회", + "description": "월간 근태 통계를 조회합니다.", + "operationId": "bbd233d7079f92d16c24208c08d47446", + "parameters": [ + { + "name": "year", + "in": "query", + "description": "연도", + "schema": { + "type": "integer", + "example": 2024 + } + }, + { + "name": "month", + "in": "query", + "description": "월", + "schema": { + "type": "integer", + "maximum": 12, + "minimum": 1, + "example": 1 + } + }, + { + "name": "user_id", + "in": "query", + "description": "특정 사용자 ID (미지정시 전체)", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/AttendanceMonthlyStats" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/attendances/check-in": { + "post": { + "tags": [ + "Attendances" + ], + "summary": "출근 기록 (체크인)", + "description": "출근 시간을 기록합니다. 당일 기록이 없으면 새로 생성, 있으면 업데이트합니다.", + "operationId": "b33a3c25a96451335ce3ea6dcc637af0", + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "user_id": { + "description": "사용자 ID (미지정시 본인)", + "type": "integer", + "example": 10 + }, + "check_in": { + "description": "출근 시간 (미지정시 현재 시간)", + "type": "string", + "example": "09:00:00" + }, + "gps_data": { + "description": "GPS 데이터", + "properties": { + "latitude": { + "type": "number", + "format": "float", + "example": 37.5665 + }, + "longitude": { + "type": "number", + "format": "float", + "example": 126.978 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "출근 기록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Attendance" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/attendances/check-out": { + "post": { + "tags": [ + "Attendances" + ], + "summary": "퇴근 기록 (체크아웃)", + "description": "퇴근 시간을 기록합니다. 출근 기록이 없으면 에러가 발생합니다.", + "operationId": "a6ae28fde4fbf4beebc19c9962f5c8b7", + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "user_id": { + "description": "사용자 ID (미지정시 본인)", + "type": "integer", + "example": 10 + }, + "check_out": { + "description": "퇴근 시간 (미지정시 현재 시간)", + "type": "string", + "example": "18:00:00" + }, + "gps_data": { + "description": "GPS 데이터", + "properties": { + "latitude": { + "type": "number", + "format": "float", + "example": 37.5665 + }, + "longitude": { + "type": "number", + "format": "float", + "example": 126.978 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "퇴근 기록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Attendance" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "출근 기록 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/attendances/{id}": { + "get": { + "tags": [ + "Attendances" + ], + "summary": "근태 상세 조회", + "description": "ID 기준 근태 상세 정보를 조회합니다.", + "operationId": "3d01da859a1cf850a2baa7456f770068", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "근태 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Attendance" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "근태 기록을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Attendances" + ], + "summary": "근태 삭제", + "description": "근태 기록을 삭제합니다 (소프트 삭제).", + "operationId": "d7427274c39eeec65dcaee048edc70a3", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "근태 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제 완료" + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "근태 기록을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Attendances" + ], + "summary": "근태 수정", + "description": "근태 기록을 수정합니다.", + "operationId": "3ff5cd4d20fca9c33b0b7be3faa526e4", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "근태 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AttendanceUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Attendance" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "근태 기록을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/attendances/bulk-delete": { + "post": { + "tags": [ + "Attendances" + ], + "summary": "근태 일괄 삭제", + "description": "여러 근태 기록을 일괄 삭제합니다.", + "operationId": "de3aca6fc757cdc9b8197d678edd594f", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "ids" + ], + "properties": { + "ids": { + "description": "삭제할 근태 ID 목록", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "일괄 삭제 완료" + }, + "data": { + "properties": { + "deleted_count": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/audit-logs": { + "get": { + "tags": [ + "Design Audit" + ], + "summary": "List audit logs", + "operationId": "16ed858f56b56911d4eb0748ed317dcb", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "maximum": 200, + "minimum": 1 + } + }, + { + "name": "target_type", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "target_id", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "action", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "actor_id", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "List", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "current_page": { + "type": "integer" + }, + "data": { + "type": "array", + "items": { + "properties": { + "tenant_id": { + "type": "integer" + }, + "target_type": { + "type": "string" + }, + "target_id": { + "type": "integer", + "nullable": true + }, + "action": { + "type": "string" + }, + "before": { + "type": "object", + "nullable": true + }, + "after": { + "type": "object", + "nullable": true + }, + "actor_id": { + "type": "integer", + "nullable": true + }, + "ip": { + "type": "string", + "nullable": true + }, + "ua": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/debug-apikey": { + "get": { + "tags": [ + "Auth" + ], + "summary": "API Key 인증 확인", + "description": "API Key가 유효한지 확인합니다. Bearer 토큰은 선택사항입니다.", + "operationId": "6f9a5e3d875616da751769476d7e7d5b", + "responses": { + "200": { + "description": "API Key 인증 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "API Key 인증 성공" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } } }, "security": [ @@ -45,8 +6849,9 @@ "tags": [ "Auth" ], - "summary": "회원 토큰 정보확인", - "operationId": "3878a009ac5aef1ebe0e72b7716e24ac", + "summary": "로그인 (토큰 + 사용자 정보 + 테넌트 + 메뉴 + 역할)", + "description": "로그인 성공 시 인증 토큰과 함께 사용자 정보, 활성 테넌트 정보, 접근 가능한 메뉴 목록, 역할 목록을 반환합니다.", + "operationId": "b98c0c67c6e60ff8dbe75665c9294e11", "requestBody": { "required": true, "content": { @@ -59,11 +6864,11 @@ "properties": { "user_id": { "type": "string", - "example": "test" + "example": "TestUser5" }, "user_pwd": { "type": "string", - "example": "testpass" + "example": "password123!" } }, "type": "object" @@ -79,10 +6884,435 @@ "schema": { "properties": { "message": { - "type": "string" + "type": "string", + "example": "로그인 성공" }, - "user_token": { - "type": "string" + "access_token": { + "description": "액세스 토큰 (API 호출에 사용)", + "type": "string", + "example": "1|abc123xyz456" + }, + "refresh_token": { + "description": "리프레시 토큰 (액세스 토큰 갱신에 사용)", + "type": "string", + "example": "2|def456uvw789" + }, + "token_type": { + "description": "토큰 타입", + "type": "string", + "example": "Bearer" + }, + "expires_in": { + "description": "액세스 토큰 만료 시간 (초 단위, null이면 무제한)", + "type": "integer", + "example": 7200, + "nullable": true + }, + "expires_at": { + "description": "액세스 토큰 만료 시각 (null이면 무제한)", + "type": "string", + "example": "2025-11-10 16:00:00", + "nullable": true + }, + "user": { + "description": "사용자 기본 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "string", + "example": "hamss" + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hamss@example.com" + }, + "phone": { + "type": "string", + "example": "010-1234-5678", + "nullable": true + } + }, + "type": "object" + }, + "tenant": { + "description": "활성 테넌트 정보 (is_default=1 우선, 없으면 is_active=1 중 첫 번째, 없으면 null)", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "company_name": { + "type": "string", + "example": "주식회사 코드브리지" + }, + "business_num": { + "type": "string", + "example": "123-45-67890", + "nullable": true + }, + "tenant_st_code": { + "type": "string", + "example": "ACTIVE", + "nullable": true + }, + "other_tenants": { + "description": "사용자가 소속된 다른 활성 테넌트 목록", + "type": "array", + "items": { + "properties": { + "tenant_id": { + "type": "integer", + "example": 2 + }, + "company_name": { + "type": "string", + "example": "주식회사 샘플" + }, + "business_num": { + "type": "string", + "example": "987-65-43210", + "nullable": true + }, + "tenant_st_code": { + "type": "string", + "example": "ACTIVE", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object", + "nullable": true + }, + "menus": { + "description": "사용자가 접근 가능한 메뉴 목록 (menu:{menu_id}.view 권한 체크, override deny/allow 적용)", + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "type": "string", + "example": "대시보드" + }, + "url": { + "type": "string", + "example": "/dashboard", + "nullable": true + }, + "icon": { + "type": "string", + "example": "dashboard", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "is_external": { + "description": "외부 링크 여부", + "type": "boolean", + "example": false + }, + "external_url": { + "description": "외부 링크 URL", + "type": "string", + "example": "https://example.com", + "nullable": true + } + }, + "type": "object" + } + }, + "roles": { + "description": "사용자가 가진 역할 목록", + "type": "array", + "items": { + "properties": { + "id": { + "description": "역할 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "역할명", + "type": "string", + "example": "system_manager" + }, + "description": { + "description": "역할 설명", + "type": "string", + "example": "시스템 관리자" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "200 (테넌트 없음)": { + "description": "로그인 성공 - 활성 테넌트 없는 경우", + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "로그인 성공" + }, + "access_token": { + "description": "액세스 토큰 (API 호출에 사용)", + "type": "string", + "example": "1|abc123xyz456" + }, + "refresh_token": { + "description": "리프레시 토큰 (액세스 토큰 갱신에 사용)", + "type": "string", + "example": "2|def456uvw789" + }, + "token_type": { + "description": "토큰 타입", + "type": "string", + "example": "Bearer" + }, + "expires_in": { + "description": "액세스 토큰 만료 시간 (초 단위, null이면 무제한)", + "type": "integer", + "example": 7200, + "nullable": true + }, + "expires_at": { + "description": "액세스 토큰 만료 시각 (null이면 무제한)", + "type": "string", + "example": "2025-11-10 16:00:00", + "nullable": true + }, + "user": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "string", + "example": "hamss" + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hamss@example.com" + }, + "phone": { + "type": "string", + "example": "010-1234-5678", + "nullable": true + } + }, + "type": "object" + }, + "tenant": { + "type": "null", + "example": null + }, + "menus": { + "type": "array", + "items": {} + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "로그인 실패 (비밀번호 불일치)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "사용자를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/token-login": { + "post": { + "tags": [ + "Auth" + ], + "summary": "토큰 로그인 (1회용 토큰으로 로그인)", + "description": "MNG에서 발급된 1회용 로그인 토큰으로 인증합니다. 토큰은 사용 후 즉시 폐기됩니다.", + "operationId": "90af4c51ab0516c37cf7fe1df03a7f67", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "token" + ], + "properties": { + "token": { + "description": "1회용 로그인 토큰", + "type": "string", + "example": "abc123xyz456" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "로그인 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "로그인 성공" + }, + "access_token": { + "type": "string", + "example": "1|abc123xyz456" + }, + "refresh_token": { + "type": "string", + "example": "2|def456uvw789" + }, + "token_type": { + "type": "string", + "example": "Bearer" + }, + "expires_in": { + "type": "integer", + "example": 7200, + "nullable": true + }, + "expires_at": { + "type": "string", + "example": "2025-11-10 16:00:00", + "nullable": true + }, + "user": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "string", + "example": "hamss" + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hamss@example.com" + }, + "phone": { + "type": "string", + "example": "010-1234-5678", + "nullable": true + } + }, + "type": "object" + }, + "tenant": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "company_name": { + "type": "string", + "example": "주식회사 코드브리지" + } + }, + "type": "object", + "nullable": true + }, + "menus": { + "type": "array", + "items": { + "type": "object" + } + }, + "roles": { + "type": "array", + "items": { + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "토큰 누락", + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "type": "string", + "example": "토큰이 필요합니다." } }, "type": "object" @@ -91,7 +7321,20 @@ } }, "401": { - "description": "로그인 실패" + "description": "유효하지 않거나 만료된 토큰", + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "type": "string", + "example": "유효하지 않거나 만료된 토큰입니다." + } + }, + "type": "object" + } + } + } } }, "security": [ @@ -107,10 +7350,8022 @@ "Auth" ], "summary": "로그아웃 (Access 및 Token 무효화)", - "operationId": "39200ed8c17c34aa7af9a24f064e13a4", + "operationId": "1f1851015c3096425b6a4fd04c52054c", "responses": { "200": { - "description": "로그아웃 성공" + "description": "로그아웃 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "로그아웃 완료" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/signup": { + "post": { + "tags": [ + "Auth" + ], + "summary": "회원가입", + "description": "신규 회원을 생성합니다. (API Key 필요)", + "operationId": "53307f8fef91b46ea5feb6ccce58bd08", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SignupRequest" + } + } + } + }, + "responses": { + "200": { + "description": "회원가입 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "user": { + "$ref": "#/components/schemas/MemberBrief" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패(API Key 누락/오류)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/bad-debts": { + "get": { + "tags": [ + "BadDebt" + ], + "summary": "악성채권 목록 조회", + "operationId": "9c524bec4ebb4d33c069078cc9e55fe3", + "parameters": [ + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "collecting", + "legal_action", + "recovered", + "bad_debt" + ] + } + }, + { + "name": "is_active", + "in": "query", + "description": "활성화 여부", + "schema": { + "type": "boolean" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (거래처명, 거래처코드)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at" + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadDebtPagination" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "BadDebt" + ], + "summary": "악성채권 등록", + "operationId": "4cf95980bb5a11fd1d0c7f272406731d", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadDebtCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BadDebt" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bad-debts/summary": { + "get": { + "tags": [ + "BadDebt" + ], + "summary": "악성채권 요약 통계", + "operationId": "de6018515647d8abf6fcb06f51f5b9a2", + "parameters": [ + { + "name": "client_id", + "in": "query", + "description": "거래처 ID (선택)", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BadDebtSummary" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bad-debts/{id}": { + "get": { + "tags": [ + "BadDebt" + ], + "summary": "악성채권 상세 조회", + "operationId": "46e6611e57131fd7c249593d7940252b", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BadDebt" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "BadDebt" + ], + "summary": "악성채권 수정", + "operationId": "78e73d0e01a5004c1857140dccd9b4e7", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadDebtUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BadDebt" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "BadDebt" + ], + "summary": "악성채권 삭제", + "operationId": "944170ea2f455a75ff2beea1772918ea", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "null" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bad-debts/{id}/toggle": { + "patch": { + "tags": [ + "BadDebt" + ], + "summary": "악성채권 설정 ON/OFF 토글", + "operationId": "65cafe1d58942c2a18821238230ef5ed", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "토글 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BadDebt" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bad-debts/{id}/documents": { + "post": { + "tags": [ + "BadDebt" + ], + "summary": "서류 첨부", + "operationId": "37e1b66a9ef363780f4354838af52399", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadDebtDocumentCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "첨부 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BadDebtDocument" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bad-debts/{id}/documents/{documentId}": { + "delete": { + "tags": [ + "BadDebt" + ], + "summary": "서류 삭제", + "operationId": "a3eb43c4d44d415a237ffffa0ae5a573", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "documentId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "null" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bad-debts/{id}/memos": { + "post": { + "tags": [ + "BadDebt" + ], + "summary": "메모 추가", + "operationId": "2fb9347535c77f0278875b3356ace5a0", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadDebtMemoCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "추가 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BadDebtMemo" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bad-debts/{id}/memos/{memoId}": { + "delete": { + "tags": [ + "BadDebt" + ], + "summary": "메모 삭제", + "operationId": "aac1f66ecb57086a0ed4a8403e9e7daf", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "memoId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "null" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bank-accounts": { + "get": { + "tags": [ + "BankAccounts" + ], + "summary": "계좌 목록 조회", + "description": "계좌 목록을 조회합니다.", + "operationId": "1524e5f7db08dca39c5173a07cf61c0c", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (계좌명, 은행명, 예금주, 계좌번호)", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + } + }, + { + "name": "assigned_user_id", + "in": "query", + "description": "담당자 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "is_primary", + "in": "query", + "description": "대표계좌만", + "schema": { + "type": "boolean" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "account_name", + "bank_name", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BankAccount" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "BankAccounts" + ], + "summary": "계좌 등록", + "description": "새로운 계좌를 등록합니다. 첫 번째 계좌는 자동으로 대표계좌로 설정됩니다.", + "operationId": "780bdcd49da08c19cef6bea639ddd265", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BankAccount" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bank-accounts/active": { + "get": { + "tags": [ + "BankAccounts" + ], + "summary": "활성 계좌 목록 (셀렉트박스용)", + "description": "활성 상태의 계좌 목록을 간단한 형태로 조회합니다.", + "operationId": "a974c06c80a14879fb85e6842ab543de", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BankAccountListItem" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bank-accounts/{id}": { + "get": { + "tags": [ + "BankAccounts" + ], + "summary": "계좌 상세 조회", + "description": "계좌 상세 정보를 조회합니다.", + "operationId": "2b0af1b63c081fffd9817afebc562123", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "계좌 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BankAccount" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "계좌 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "BankAccounts" + ], + "summary": "계좌 수정", + "description": "계좌 정보를 수정합니다.", + "operationId": "4a1b9ecae47808e23c4286b54c9272dd", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "계좌 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BankAccount" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "계좌 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "BankAccounts" + ], + "summary": "계좌 삭제", + "description": "계좌를 삭제합니다. (Soft Delete) 대표계좌 삭제 시 다른 활성 계좌가 대표계좌로 자동 설정됩니다.", + "operationId": "dd68774c92f9f8def6d386aadb0cdd5b", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "계좌 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "계좌 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bank-accounts/{id}/toggle": { + "patch": { + "tags": [ + "BankAccounts" + ], + "summary": "계좌 상태 토글", + "description": "계좌의 상태를 토글합니다. (active ↔ inactive)", + "operationId": "307951eebd919c3cd3ad3e80d7ba7f23", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "계좌 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "토글 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BankAccount" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "계좌 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bank-accounts/{id}/set-primary": { + "patch": { + "tags": [ + "BankAccounts" + ], + "summary": "대표계좌 설정", + "description": "해당 계좌를 대표계좌로 설정합니다. 기존 대표계좌는 자동으로 해제됩니다.", + "operationId": "7d53e459de6b2e4336ef8e4e3498f53f", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "계좌 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "설정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BankAccount" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "계좌 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bank-transactions": { + "get": { + "tags": [ + "BankTransaction" + ], + "summary": "입출금 통합 목록 조회", + "description": "은행 계좌의 입출금 내역을 통합 조회합니다.", + "operationId": "getBankTransactionList", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "조회 시작일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "조회 종료일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + }, + { + "name": "bank_account_id", + "in": "query", + "description": "계좌 ID 필터", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "transaction_type", + "in": "query", + "description": "입출금 유형 필터 (unset: 미설정)", + "schema": { + "type": "string", + "example": "salesRevenue" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (은행명, 계좌명, 거래처, 적요)", + "schema": { + "type": "string", + "example": "국민" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "transaction_date", + "enum": [ + "transaction_date", + "amount" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/BankTransactionPagination" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bank-transactions/summary": { + "get": { + "tags": [ + "BankTransaction" + ], + "summary": "입출금 요약 통계", + "description": "입금/출금 합계 및 유형 미설정 건수를 조회합니다.", + "operationId": "getBankTransactionSummary", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "조회 시작일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "조회 종료일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/BankTransactionSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bank-transactions/accounts": { + "get": { + "tags": [ + "BankTransaction" + ], + "summary": "계좌 목록 조회 (필터용)", + "description": "입출금 조회 필터에 사용할 계좌 목록을 조회합니다.", + "operationId": "getBankTransactionAccounts", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BankAccountOption" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/barobill-settings": { + "get": { + "tags": [ + "BarobillSettings" + ], + "summary": "바로빌 설정 조회", + "description": "현재 테넌트의 바로빌 설정을 조회합니다. 설정이 없는 경우 null을 반환합니다.", + "operationId": "29543cb89a989c171ffe398dc5023380", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/BarobillSetting" + } + ], + "nullable": true + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "BarobillSettings" + ], + "summary": "바로빌 설정 저장", + "description": "바로빌 설정을 저장합니다. 기존 설정이 있으면 수정하고, 없으면 새로 생성합니다. cert_key는 암호화되어 저장됩니다.", + "operationId": "ef471b76c8b09342eb27169420da2c37", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BarobillSettingSaveRequest" + } + } + } + }, + "responses": { + "200": { + "description": "저장 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BarobillSetting" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/barobill-settings/test-connection": { + "post": { + "tags": [ + "BarobillSettings" + ], + "summary": "바로빌 연동 테스트", + "description": "저장된 바로빌 설정으로 연동 테스트를 수행합니다. 설정이 없거나 필수 값이 누락되면 에러를 반환합니다.", + "operationId": "6d1af93a2a204337e5080e2109007dc0", + "responses": { + "200": { + "description": "연동 테스트 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BarobillConnectionTestResult" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "설정 미완료 또는 연동 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/biddings": { + "get": { + "tags": [ + "Bidding" + ], + "summary": "입찰 목록 조회", + "description": "입찰 목록을 페이징하여 조회합니다.", + "operationId": "3796d06414b0a456d3afa58a7ad933e1", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "검색어 (입찰번호, 현장명, 거래처명)", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "waiting", + "submitted", + "failed", + "invalid", + "awarded", + "hold" + ] + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "bidder_id", + "in": "query", + "description": "입찰담당자 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "date_from", + "in": "query", + "description": "입찰일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "date_to", + "in": "query", + "description": "입찰일 종료", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "bidding_date" + } + }, + { + "name": "sort_order", + "in": "query", + "description": "정렬 순서", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BiddingPagination" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/biddings/stats": { + "get": { + "tags": [ + "Bidding" + ], + "summary": "입찰 통계 조회", + "description": "상태별 입찰 건수와 금액을 조회합니다.", + "operationId": "34bdba27328b9fe3c5b6c5d943a05429", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/BiddingStats" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/biddings/{id}": { + "get": { + "tags": [ + "Bidding" + ], + "summary": "입찰 단건 조회", + "description": "입찰 상세 정보를 조회합니다.", + "operationId": "b93c287898947943e7f2dab423834ca4", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Bidding" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "입찰을 찾을 수 없습니다" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Bidding" + ], + "summary": "입찰 수정", + "description": "입찰 정보를 수정합니다.", + "operationId": "7875c983dd7a81531743bad1e626a458", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BiddingUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Bidding" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "입찰을 찾을 수 없습니다" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Bidding" + ], + "summary": "입찰 삭제", + "description": "입찰을 삭제합니다 (Soft Delete).", + "operationId": "5b9a372952fefd3306fe2b0c2edd810c", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "null" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "입찰을 찾을 수 없습니다" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/biddings/bulk": { + "delete": { + "tags": [ + "Bidding" + ], + "summary": "입찰 일괄 삭제", + "description": "여러 입찰을 일괄 삭제합니다 (Soft Delete).", + "operationId": "c089f949614e342162591a03cac2a1fa", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BiddingBulkDeleteRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "deleted_count": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/biddings/{id}/status": { + "patch": { + "tags": [ + "Bidding" + ], + "summary": "입찰 상태 변경", + "description": "입찰 상태를 변경합니다.", + "operationId": "f3ade8ce4ad715e179d513f25fb452df", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BiddingStatusRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Bidding" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "입찰을 찾을 수 없습니다" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}/convert-to-bidding": { + "post": { + "tags": [ + "Bidding" + ], + "summary": "견적을 입찰로 변환", + "description": "시공 견적을 입찰로 변환합니다. 견적 데이터 스냅샷이 저장됩니다.", + "operationId": "2f7abf05b5613a0ea309a309e1e6416e", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "견적 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Bidding" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "견적을 찾을 수 없습니다" + }, + "400": { + "description": "이미 입찰로 변환된 견적입니다" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bills": { + "get": { + "tags": [ + "Bills" + ], + "summary": "어음 목록 조회", + "description": "어음 목록을 페이지네이션하여 조회합니다.", + "operationId": "getBills", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (어음번호, 거래처명, 메모)", + "schema": { + "type": "string" + } + }, + { + "name": "bill_type", + "in": "query", + "description": "어음 구분", + "schema": { + "type": "string", + "enum": [ + "received", + "issued" + ] + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "is_electronic", + "in": "query", + "description": "전자어음 여부", + "schema": { + "type": "boolean" + } + }, + { + "name": "issue_start_date", + "in": "query", + "description": "발행일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "issue_end_date", + "in": "query", + "description": "발행일 종료", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "maturity_start_date", + "in": "query", + "description": "만기일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "maturity_end_date", + "in": "query", + "description": "만기일 종료", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "issue_date" + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 건수", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/BillPagination" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Bills" + ], + "summary": "어음 등록", + "description": "새로운 어음을 등록합니다.", + "operationId": "storeBill", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BillCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "생성되었습니다." + }, + "data": { + "$ref": "#/components/schemas/Bill" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검사 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bills/{id}": { + "get": { + "tags": [ + "Bills" + ], + "summary": "어음 상세 조회", + "description": "특정 어음의 상세 정보를 조회합니다.", + "operationId": "showBill", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "어음 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/Bill" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "어음을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Bills" + ], + "summary": "어음 수정", + "description": "기존 어음 정보를 수정합니다.", + "operationId": "updateBill", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "어음 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BillUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "수정되었습니다." + }, + "data": { + "$ref": "#/components/schemas/Bill" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "어음을 찾을 수 없음" + }, + "422": { + "description": "유효성 검사 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Bills" + ], + "summary": "어음 삭제", + "description": "어음을 삭제합니다. (Soft Delete)", + "operationId": "deleteBill", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "어음 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제되었습니다." + }, + "data": { + "type": "null" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "어음을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bills/{id}/status": { + "patch": { + "tags": [ + "Bills" + ], + "summary": "어음 상태 변경", + "description": "어음의 상태를 변경합니다.", + "operationId": "updateBillStatus", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "어음 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "status" + ], + "properties": { + "status": { + "description": "변경할 상태", + "type": "string", + "example": "paymentComplete" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "상태 변경 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "수정되었습니다." + }, + "data": { + "$ref": "#/components/schemas/Bill" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "어음을 찾을 수 없음" + }, + "422": { + "description": "유효성 검사 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bills/summary": { + "get": { + "tags": [ + "Bills" + ], + "summary": "어음 요약 조회", + "description": "기간별 어음 요약 정보를 조회합니다.", + "operationId": "getBillSummary", + "parameters": [ + { + "name": "bill_type", + "in": "query", + "description": "어음 구분", + "schema": { + "type": "string", + "enum": [ + "received", + "issued" + ] + } + }, + { + "name": "issue_start_date", + "in": "query", + "description": "발행일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "issue_end_date", + "in": "query", + "description": "발행일 종료", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "maturity_start_date", + "in": "query", + "description": "만기일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "maturity_end_date", + "in": "query", + "description": "만기일 종료", + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/BillSummary" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/bills/dashboard-detail": { + "get": { + "tags": [ + "Bills" + ], + "summary": "발행어음 대시보드 상세 조회", + "description": "CEO 대시보드 당월 예상 지출내역 me3 모달용 상세 데이터를 조회합니다. 요약 정보, 월별 추이, 거래처별 분포, 발행어음 목록을 제공합니다.", + "operationId": "getBillDashboardDetail", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/BillDashboardDetail" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards": { + "get": { + "tags": [ + "Board" + ], + "summary": "접근 가능한 게시판 목록 (시스템 + 테넌트)", + "operationId": "ef5cdad8bc0f898cb46e2892fcf3cab0", + "parameters": [ + { + "name": "board_type", + "in": "query", + "description": "게시판 유형 필터", + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "게시판명 검색", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Board" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Board" + ], + "summary": "테넌트 게시판 생성", + "description": "현재 테넌트에 새 게시판을 생성합니다. 시스템 게시판은 mng에서만 생성 가능합니다.", + "operationId": "d1d828f2924addfc1097d7f2ed18fbb5", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BoardCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Board" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards/tenant": { + "get": { + "tags": [ + "Board" + ], + "summary": "테넌트 게시판 목록만 조회", + "operationId": "6792d84f1ef3fc9122719577154d0bbc", + "parameters": [ + { + "name": "board_type", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Board" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards/{code}": { + "get": { + "tags": [ + "Board" + ], + "summary": "게시판 상세 조회 (코드 기반)", + "operationId": "269da54746b3c9b19e4e49f844c96c05", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Board" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards/{id}": { + "put": { + "tags": [ + "Board" + ], + "summary": "테넌트 게시판 수정", + "description": "테넌트 게시판만 수정 가능. 시스템 게시판은 수정 불가.", + "operationId": "a16ec17e90c7274fadc20f0e129c6bea", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BoardUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Board" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Board" + ], + "summary": "테넌트 게시판 삭제", + "description": "테넌트 게시판만 삭제 가능. 시스템 게시판은 삭제 불가.", + "operationId": "dd2c045d26f0966426caea3373aeb4e0", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards/{code}/fields": { + "get": { + "tags": [ + "Board" + ], + "summary": "게시판 커스텀 필드 목록", + "operationId": "2dcd61e035bcad689c11ddfa91ad7fda", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BoardField" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/models/{modelId}/estimate-parameters": { + "get": { + "tags": [ + "BOM Calculation" + ], + "summary": "견적 파라미터 조회", + "description": "특정 모델의 견적 시 필요한 입력 파라미터 스키마를 조회합니다. BOM에 정의된 조건만 동적으로 추출하여 반환합니다.", + "operationId": "9b09ce35833cf163697f245fa9e74840", + "parameters": [ + { + "name": "modelId", + "in": "path", + "description": "모델 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "company_name", + "in": "query", + "description": "업체명 (선택사항)", + "required": false, + "schema": { + "type": "string", + "example": "경동기업" + } + } + ], + "responses": { + "200": { + "description": "견적 파라미터 조회 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EstimateParametersResponse" + } + } + } + }, + "404": { + "description": "모델을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/bom-templates/{bomTemplateId}/calculate-bom": { + "post": { + "tags": [ + "BOM Calculation" + ], + "summary": "BOM 계산 실행", + "description": "입력된 파라미터를 기반으로 BOM 수량을 동적으로 계산합니다. 업체별 산출식을 적용하여 실시간 견적을 생성합니다.", + "operationId": "d0f4285c4c173863c6c189ee59323c62", + "parameters": [ + { + "name": "bomTemplateId", + "in": "path", + "description": "BOM 템플릿 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "requestBody": { + "description": "계산 파라미터", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CalculateBomRequest" + } + } + } + }, + "responses": { + "200": { + "description": "BOM 계산 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CalculateBomResponse" + } + } + } + }, + "400": { + "description": "잘못된 파라미터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/companies/{companyName}/formulas": { + "get": { + "tags": [ + "BOM Calculation" + ], + "summary": "업체별 산출식 목록 조회", + "description": "특정 업체의 등록된 산출식 목록을 조회합니다.", + "operationId": "e6c2e34db5b4fe01f86a4689e0dfd491", + "parameters": [ + { + "name": "companyName", + "in": "path", + "description": "업체명", + "required": true, + "schema": { + "type": "string", + "example": "경동기업" + } + } + ], + "responses": { + "200": { + "description": "업체 산출식 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompanyFormulasResponse" + } + } + } + }, + "404": { + "description": "업체를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/companies/{companyName}/formulas/{formulaType}": { + "post": { + "tags": [ + "BOM Calculation" + ], + "summary": "업체별 산출식 등록/수정", + "description": "특정 업체의 산출식을 등록하거나 수정합니다. 기존 산출식이 있으면 새 버전으로 업데이트됩니다.", + "operationId": "8b7619057f2cdd76ae1d1f3c884885f4", + "parameters": [ + { + "name": "companyName", + "in": "path", + "description": "업체명", + "required": true, + "schema": { + "type": "string", + "example": "경동기업" + } + }, + { + "name": "formulaType", + "in": "path", + "description": "산출식 타입", + "required": true, + "schema": { + "type": "string", + "example": "manufacturing_size" + } + } + ], + "requestBody": { + "description": "산출식 데이터", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveFormulaRequest" + } + } + } + }, + "responses": { + "201": { + "description": "업체 산출식 등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "company_name": { + "type": "string", + "example": "경동기업" + }, + "formula_type": { + "type": "string", + "example": "manufacturing_size" + }, + "version": { + "type": "string", + "example": "v1.0" + }, + "is_active": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-09-22T15:30:00Z" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/formulas/test": { + "post": { + "tags": [ + "BOM Calculation" + ], + "summary": "계산식 테스트 실행", + "description": "산출식을 실제 적용하기 전에 테스트해볼 수 있습니다.", + "operationId": "29bba41925cd65ebe9310c4487d8d092", + "requestBody": { + "description": "테스트할 계산식과 파라미터", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FormulaTestRequest" + } + } + } + }, + "responses": { + "200": { + "description": "계산식 테스트 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FormulaTestResponse" + } + } + } + }, + "400": { + "description": "잘못된 계산식", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/calendar/schedules": { + "get": { + "tags": [ + "Calendar" + ], + "summary": "캘린더 일정 조회", + "description": "CEO 대시보드 캘린더의 일정 데이터를 조회합니다.\n\n * 데이터 소스:\n * - 작업지시(order): 생산 예정일 기준\n * - 계약/시공(construction): 계약 기간 기준\n * - 휴가(schedule): 승인된 휴가 기간 기준\n\n * 필터:\n * - 기간 필터: start_date ~ end_date\n * - 타입 필터: schedule(휴가), order(작업지시), construction(시공)\n * - 부서 필터: all(전체), department(부서), personal(개인)", + "operationId": "getCalendarSchedules", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "조회 시작일 (Y-m-d, 기본: 이번 달 1일)", + "required": false, + "schema": { + "type": "string", + "format": "date", + "example": "2026-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "조회 종료일 (Y-m-d, 기본: 이번 달 말일)", + "required": false, + "schema": { + "type": "string", + "format": "date", + "example": "2026-01-31" + } + }, + { + "name": "type", + "in": "query", + "description": "일정 타입 필터 (미지정 시 전체 조회)", + "required": false, + "schema": { + "type": "string", + "enum": [ + "schedule", + "order", + "construction", + "other" + ] + } + }, + { + "name": "department_filter", + "in": "query", + "description": "부서 필터 (기본: all)", + "required": false, + "schema": { + "type": "string", + "default": "all", + "enum": [ + "all", + "department", + "personal" + ] + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "$ref": "#/components/schemas/CalendarScheduleSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "인증이 필요합니다." + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "유효성 검증에 실패했습니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/cards": { + "get": { + "tags": [ + "Cards" + ], + "summary": "카드 목록 조회", + "description": "카드 목록을 조회합니다.", + "operationId": "55f362d66079bf7859df7e0ca13c2bc8", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (카드명, 카드사, 끝4자리)", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + } + }, + { + "name": "assigned_user_id", + "in": "query", + "description": "담당자 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "card_name", + "card_company", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Card" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Cards" + ], + "summary": "카드 등록", + "description": "새로운 카드를 등록합니다. 카드번호는 암호화되어 저장됩니다.", + "operationId": "3448ddb67a03a1e6e8609e24b6705c42", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Card" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/cards/active": { + "get": { + "tags": [ + "Cards" + ], + "summary": "활성 카드 목록 (셀렉트박스용)", + "description": "활성 상태의 카드 목록을 간단한 형태로 조회합니다.", + "operationId": "6f3c5662d676b1479dfd08867f5acf93", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CardListItem" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/cards/{id}": { + "get": { + "tags": [ + "Cards" + ], + "summary": "카드 상세 조회", + "description": "카드 상세 정보를 조회합니다.", + "operationId": "3318609c9211322d9eb88f0b443b82da", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "카드 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Card" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "카드 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Cards" + ], + "summary": "카드 수정", + "description": "카드 정보를 수정합니다.", + "operationId": "ec193da906fb8f625f10c8f6e8abeeb3", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "카드 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Card" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "카드 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Cards" + ], + "summary": "카드 삭제", + "description": "카드를 삭제합니다. (Soft Delete)", + "operationId": "935f7bd26ca34cda1459adaa593762a6", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "카드 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "카드 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/cards/{id}/toggle": { + "patch": { + "tags": [ + "Cards" + ], + "summary": "카드 상태 토글", + "description": "카드의 상태를 토글합니다. (active ↔ inactive)", + "operationId": "38a68fc717b793ab8ae24fdead09b232", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "카드 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "토글 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Card" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "카드 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/card-transactions": { + "get": { + "tags": [ + "CardTransaction" + ], + "summary": "카드 거래 목록 조회", + "description": "법인카드 사용 내역을 조회합니다.", + "operationId": "getCardTransactionList", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "조회 시작일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "조회 종료일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + }, + { + "name": "card_id", + "in": "query", + "description": "카드 ID 필터", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (카드명, 가맹점명)", + "schema": { + "type": "string", + "example": "스타벅스" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "used_at", + "enum": [ + "used_at", + "amount", + "merchant_name", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/CardTransactionPagination" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/card-transactions/summary": { + "get": { + "tags": [ + "CardTransaction" + ], + "summary": "카드 거래 요약 통계", + "description": "전월/당월 카드 사용액 통계를 조회합니다.", + "operationId": "getCardTransactionSummary", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "조회 시작일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "조회 종료일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/CardTransactionSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/card-transactions/dashboard": { + "get": { + "tags": [ + "CardTransaction" + ], + "summary": "카드 거래 대시보드 데이터", + "description": "CEO 대시보드 카드/가지급금 관리 섹션(cm1)의 모달 팝업용 상세 데이터를 조회합니다. 요약 통계, 월별 추이, 사용자별 비율, 최근 거래 목록을 포함합니다.", + "operationId": "getCardTransactionDashboard", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/CardTransactionDashboard" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/card-transactions/bulk-update-account": { + "put": { + "tags": [ + "CardTransaction" + ], + "summary": "계정과목 일괄 수정", + "description": "선택한 카드 거래들의 계정과목을 일괄 수정합니다.", + "operationId": "bulkUpdateCardTransactionAccountCode", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardTransactionBulkUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 수정했습니다." + }, + "data": { + "properties": { + "updated_count": { + "description": "수정된 건수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + }, + "422": { + "description": "유효성 검사 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/card-transactions/{id}": { + "get": { + "tags": [ + "CardTransaction" + ], + "summary": "카드 거래 상세 조회", + "description": "특정 카드 거래의 상세 정보를 조회합니다.", + "operationId": "getCardTransaction", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "거래 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/CardTransactionItem" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + }, + "404": { + "description": "거래를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories": { + "get": { + "tags": [ + "Category" + ], + "summary": "카테고리 목록", + "operationId": "9dfb2569b0591f2d50167133fdbf9408", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "example": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "코드/이름 검색", + "schema": { + "type": "string" + } + }, + { + "name": "parent_id", + "in": "query", + "schema": { + "type": "integer", + "nullable": true + } + }, + { + "name": "only_active", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Category" + ], + "summary": "카테고리 생성", + "operationId": "cf6826efe0e35ff9b8b058f06bd21607", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CategoryCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Category" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}": { + "get": { + "tags": [ + "Category" + ], + "summary": "카테고리 단건 조회", + "operationId": "917acd35d29fcc619f4235109703755a", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Category" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Category" + ], + "summary": "카테고리 삭제(soft)", + "operationId": "3a6ebaf31d83b625053a11632609715f", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Category" + ], + "summary": "카테고리 수정", + "operationId": "c5d16e073e43505198ed3a5558ca7af7", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CategoryUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Category" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/toggle": { + "post": { + "tags": [ + "Category" + ], + "summary": "활성/비활성 토글", + "operationId": "6e56172eba67b116543d734800997e7a", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Category" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/move": { + "patch": { + "tags": [ + "Category" + ], + "summary": "부모/순서 이동", + "operationId": "5d499802abc8b84010bb18dcc4578c74", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "parent_id": { + "type": "integer", + "nullable": true + }, + "sort_order": { + "type": "integer", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "이동 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Category" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/reorder": { + "post": { + "tags": [ + "Category" + ], + "summary": "정렬순서 일괄 변경", + "operationId": "a830e3136e4f2667de993b749e6e5330", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "items": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "저장 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/tree": { + "get": { + "tags": [ + "Category" + ], + "summary": "카테고리 트리", + "operationId": "066b788e2d1267f1aa11a34a00a473d2", + "parameters": [ + { + "name": "only_active", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CategoryTreeNode" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/fields": { + "get": { + "tags": [ + "Category-Fields" + ], + "summary": "카테고리별 필드 목록", + "operationId": "79e4505d1914302c2ba0278e5444bf49", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "카테고리 ID", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + }, + { + "name": "sort", + "in": "query", + "schema": { + "type": "string", + "example": "sort_order" + } + }, + { + "name": "order", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "example": "asc" + } + } + ], + "responses": { + "200": { + "description": "목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryFieldPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Category-Fields" + ], + "summary": "카테고리 필드 생성", + "operationId": "24bd4bc50932890c3d5b14499cc2076f", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CategoryFieldCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryField" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/fields/{field}": { + "get": { + "tags": [ + "Category-Fields" + ], + "summary": "카테고리 필드 단건 조회", + "operationId": "5b36f3cfee3218e75a4f1b30fb32f1b8", + "parameters": [ + { + "name": "field", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryField" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Category-Fields" + ], + "summary": "카테고리 필드 삭제", + "operationId": "b721a57841a076815eac35f89b425a3f", + "parameters": [ + { + "name": "field", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Category-Fields" + ], + "summary": "카테고리 필드 수정", + "operationId": "4abb3a617cf18ebea69b2412d0c2f4ce", + "parameters": [ + { + "name": "field", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CategoryFieldUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryField" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/fields/reorder": { + "post": { + "tags": [ + "Category-Fields" + ], + "summary": "카테고리 필드 정렬 저장", + "operationId": "d54e4f650902657cd5b7c0dec46f1847", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CategoryFieldReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "저장 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/fields/bulk-upsert": { + "put": { + "tags": [ + "Category-Fields" + ], + "summary": "카테고리 필드 일괄 업서트", + "operationId": "c31bc43493ef0b5232febdc18e2a6c1f", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CategoryFieldBulkUpsertRequest" + } + } + } + }, + "responses": { + "200": { + "description": "업서트 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "created": { + "type": "integer", + "example": 2 + }, + "updated": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/templates": { + "get": { + "tags": [ + "Category-Templates" + ], + "summary": "카테고리 템플릿 버전 목록", + "operationId": "4796e043b4efa6b7b31799e932fa84d8", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CategoryTemplate" + } + }, + "total": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Category-Templates" + ], + "summary": "카테고리 템플릿 생성(새 버전)", + "operationId": "0bc562dc410918a70bcdddcfeb7efd44", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CategoryTemplateCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryTemplate" + } + }, + "type": "object" + } + ] + } + } + } + }, + "409": { + "description": "버전 중복", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/templates/{tpl}": { + "get": { + "tags": [ + "Category-Templates" + ], + "summary": "카테고리 템플릿 단건 조회", + "operationId": "86aba298b525819f3196079c4dd9c54f", + "parameters": [ + { + "name": "tpl", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryTemplate" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Category-Templates" + ], + "summary": "카테고리 템플릿 삭제", + "operationId": "a7410e16a4b70ecc844d63fac69cd2a2", + "parameters": [ + { + "name": "tpl", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Category-Templates" + ], + "summary": "카테고리 템플릿 수정", + "operationId": "5520cf7e2e960fc804ab3b407061a167", + "parameters": [ + { + "name": "tpl", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CategoryTemplateUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryTemplate" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/templates/{tpl}/apply": { + "post": { + "tags": [ + "Category-Templates" + ], + "summary": "카테고리 템플릿 적용(활성화)", + "operationId": "45aeff70745dece9ef64cf198fc1f2d8", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "tpl", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "적용 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/templates/{tpl}/preview": { + "get": { + "tags": [ + "Category-Templates" + ], + "summary": "카테고리 템플릿 미리보기", + "operationId": "fababa4c826f648ce405f18b554466e2", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "tpl", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "미리보기 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/templates/diff": { + "get": { + "tags": [ + "Category-Templates" + ], + "summary": "두 버전 비교(diff)", + "operationId": "547695d96c378d4768c12e573bd6b214", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "a", + "in": "query", + "description": "비교 기준 버전", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "b", + "in": "query", + "description": "비교 대상 버전", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "비교 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "added": { + "type": "array", + "items": { + "type": "string" + } + }, + "removed": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/{id}/logs": { + "get": { + "tags": [ + "Category-Logs" + ], + "summary": "카테고리 변경 이력 목록", + "operationId": "379707f3c0cc191043f2ab5d97d4a6ab", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "action", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "insert", + "update", + "delete" + ] + } + }, + { + "name": "from", + "in": "query", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "to", + "in": "query", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CategoryLog" + } + }, + "total": { + "type": "integer", + "example": 12 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/categories/logs/{log}": { + "get": { + "tags": [ + "Category-Logs" + ], + "summary": "카테고리 변경 이력 단건 조회", + "operationId": "a7d4cb59bad924379fe2bc659d31c4ec", + "parameters": [ + { + "name": "log", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CategoryLog" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/classifications": { + "get": { + "tags": [ + "Classification" + ], + "summary": "분류 목록", + "description": "그룹/검색/활성여부 조건으로 분류 목록을 페이징 반환합니다.", + "operationId": "572dd9379142c1140319d13eccdeab12", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "example": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "코드/이름 검색", + "schema": { + "type": "string" + } + }, + { + "name": "group", + "in": "query", + "description": "분류 그룹 키", + "schema": { + "type": "string" + } + }, + { + "name": "only_active", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ClassificationPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Classification" + ], + "summary": "분류 생성", + "operationId": "39ec4aec7fcf7da09afdf8bf89db7735", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClassificationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Classification" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/classifications/{id}": { + "get": { + "tags": [ + "Classification" + ], + "summary": "분류 단건 조회", + "operationId": "9340ed32f486ab2464d88f87e22a9563", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Classification" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Classification" + ], + "summary": "분류 삭제(soft)", + "operationId": "65f3364e5e921e358cebd09ed15cac57", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Classification" + ], + "summary": "분류 수정", + "operationId": "5ffd066556d3374d19d77102ac5146e2", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClassificationUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Classification" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/clients": { + "get": { + "tags": [ + "Client" + ], + "summary": "거래처 목록", + "operationId": "ce67333f551df4e1fdeccb07e5bf5545", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "example": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "거래처 코드/이름 검색", + "schema": { + "type": "string" + } + }, + { + "name": "only_active", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ClientPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Client" + ], + "summary": "거래처 생성", + "operationId": "e5b8b51ce9cc90f81e3de10f5ecf8990", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Client" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/clients/{id}": { + "get": { + "tags": [ + "Client" + ], + "summary": "거래처 단건 조회", + "operationId": "8eb353ba0db90b4d3dfb742aec018f5e", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Client" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Client" + ], + "summary": "거래처 수정", + "operationId": "48350431ab22822edc5b2e85785d27b8", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Client" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Client" + ], + "summary": "거래처 삭제", + "description": "주문이 존재하는 거래처는 삭제할 수 없습니다.", + "operationId": "30ef09ebfb7a9828862976f83875d7f3", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "주문 존재로 삭제 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/clients/{id}/toggle": { + "patch": { + "tags": [ + "Client" + ], + "summary": "활성/비활성 토글", + "operationId": "5959d2132558c2f0d75ebe83a9875540", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Client" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/client-groups": { + "get": { + "tags": [ + "ClientGroup" + ], + "summary": "고객 그룹 목록", + "operationId": "421f67cf40a70ef5c2cad356e9b508f1", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "example": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "그룹 코드/이름 검색", + "schema": { + "type": "string" + } + }, + { + "name": "only_active", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ClientGroupPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ClientGroup" + ], + "summary": "고객 그룹 생성", + "description": "고객 그룹을 생성합니다. 같은 group_code로 이전에 삭제된 그룹이 있으면 자동으로 복원하고 새 데이터로 업데이트합니다.", + "operationId": "36ebfd5e0e948adae0d0d77904e059c7", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientGroupCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공 (또는 삭제된 데이터 복원)", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ClientGroup" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패 또는 중복 코드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/client-groups/{id}": { + "get": { + "tags": [ + "ClientGroup" + ], + "summary": "고객 그룹 단건 조회", + "operationId": "52b59fe36556445d6e21fa6bcbc4a1fa", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ClientGroup" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "ClientGroup" + ], + "summary": "고객 그룹 수정", + "operationId": "22090341e29366ac9626376c35d14186", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientGroupUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ClientGroup" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ClientGroup" + ], + "summary": "고객 그룹 삭제(soft)", + "operationId": "66564c7ba28dc37e98d423909e131500", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/client-groups/{id}/toggle": { + "patch": { + "tags": [ + "ClientGroup" + ], + "summary": "활성/비활성 토글", + "operationId": "eea8930ccf12bdd3eb3e1eefe4b5f3fe", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ClientGroup" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/common/code": { + "get": { + "tags": [ + "Settings - Common Codes" + ], + "summary": "공통 코드 조회", + "description": "테넌트의 활성화된 공통 코드 목록을 조회합니다.", + "operationId": "6eed12cf0b3e38b06652a53da1f91bbf", + "responses": { + "200": { + "description": "공통 코드 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "공통코드" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommonCode" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/settings/common": { + "get": { + "tags": [ + "Settings - Common Codes" + ], + "summary": "공통 코드 목록 조회", + "description": "전체 공통 코드 목록을 조회합니다.", + "operationId": "318ca6991f85c80063311d41529ef807", + "responses": { + "200": { + "description": "공통 코드 목록 조회 성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Settings - Common Codes" + ], + "summary": "공통 코드 생성", + "description": "새로운 공통 코드를 생성합니다.", + "operationId": "890f1ef57874c6e82eed5f4e1831d9c9", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommonCodeCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "공통 코드 생성 성공" + }, + "409": { + "description": "중복된 공통 코드", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "중복된 공통 코드가 존재합니다." + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/common/{group}": { + "get": { + "tags": [ + "Settings - Common Codes" + ], + "summary": "특정 그룹 공통 코드 조회", + "description": "특정 그룹의 공통 코드 목록을 조회합니다.", + "operationId": "953f61c20c1cf74e7a928b044e0111d0", + "parameters": [ + { + "name": "group", + "in": "path", + "description": "코드 그룹", + "required": true, + "schema": { + "type": "string", + "example": "product_type" + } + } + ], + "responses": { + "200": { + "description": "그룹 코드 조회 성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/common/{id}": { + "delete": { + "tags": [ + "Settings - Common Codes" + ], + "summary": "공통 코드 삭제", + "description": "공통 코드를 삭제합니다.", + "operationId": "0f84d2760016fda9ad0c3ada1a4ac182", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "공통 코드 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "공통 코드 삭제 성공" + }, + "404": { + "description": "공통 코드를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "해당 공통 코드를 찾을 수 없습니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Settings - Common Codes" + ], + "summary": "공통 코드 수정", + "description": "기존 공통 코드를 수정합니다.", + "operationId": "9f770ace9510d8868e78eb14b042fd34", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "공통 코드 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommonCodeUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "공통 코드 수정 성공" + }, + "404": { + "description": "공통 코드를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "해당 공통 코드를 찾을 수 없습니다." + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/companies/check": { + "post": { + "tags": [ + "Companies" + ], + "summary": "사업자등록번호 유효성 검사", + "description": "사업자등록번호의 유효성을 검사합니다. 바로빌 API를 통해 휴폐업 여부를 확인하고, 이미 등록된 회사인지 확인합니다.", + "operationId": "checkBusinessNumber", + "requestBody": { + "description": "사업자등록번호", + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "business_number" + ], + "properties": { + "business_number": { + "description": "사업자등록번호 (10자리, 하이픈 제거)", + "type": "string", + "example": "1234567890" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "검증 결과", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "검증이 완료되었습니다." + }, + "data": { + "$ref": "#/components/schemas/BusinessNumberCheckResponse" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "잘못된 요청" }, "401": { "description": "인증 실패" @@ -126,39 +15381,28 @@ ] } }, - "/api/v1/member/index": { - "get": { + "/api/v1/companies/request": { + "post": { "tags": [ - "Member" + "Companies" ], - "summary": "회원 목록 조회", - "description": "회원 목록을 페이징 형태로 반환합니다.", - "operationId": "9243d8df1b20c9552b21389ce84415ea", - "parameters": [ - { - "name": "page", - "in": "query", - "description": "페이지 번호 (기본값: 1)", - "required": false, - "schema": { - "type": "integer", - "example": 1 - } - }, - { - "name": "size", - "in": "query", - "description": "페이지당 항목 수 (기본값: 20)", - "required": false, - "schema": { - "type": "integer", - "example": 20 + "summary": "회사 추가 신청", + "description": "새로운 회사 추가를 신청합니다. 관리자 승인 후 테넌트가 생성됩니다.", + "operationId": "createCompanyRequest", + "requestBody": { + "description": "회사 정보", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompanyRequestCreateRequest" + } } } - ], + }, "responses": { - "200": { - "description": "회원 목록 조회 성공", + "201": { + "description": "신청 완료", "content": { "application/json": { "schema": { @@ -169,7 +15413,1682 @@ }, "message": { "type": "string", - "example": "회원목록 조회 성공" + "example": "회사 추가 신청이 완료되었습니다." + }, + "data": { + "$ref": "#/components/schemas/CompanyRequest" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "잘못된 요청 (중복 신청, 이미 등록된 회사 등)" + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/companies/requests": { + "get": { + "tags": [ + "Companies" + ], + "summary": "회사 추가 신청 목록 (관리자용)", + "description": "회사 추가 신청 목록을 조회합니다. 관리자 권한이 필요합니다.", + "operationId": "getCompanyRequests", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "pending", + "approved", + "rejected" + ] + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (사업자번호, 회사명, 신청자명)", + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "enum": [ + "created_at", + "company_name", + "status", + "processed_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "schema": { + "type": "integer", + "default": 20, + "maximum": 100, + "minimum": 1 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "minimum": 1 + } + } + ], + "responses": { + "200": { + "description": "신청 목록", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "$ref": "#/components/schemas/CompanyRequestPagination" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/companies/requests/{id}": { + "get": { + "tags": [ + "Companies" + ], + "summary": "회사 추가 신청 상세", + "description": "회사 추가 신청 상세 정보를 조회합니다.", + "operationId": "getCompanyRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "신청 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "신청 상세", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "$ref": "#/components/schemas/CompanyRequest" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "404": { + "description": "신청 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/companies/requests/{id}/approve": { + "post": { + "tags": [ + "Companies" + ], + "summary": "회사 추가 신청 승인", + "description": "회사 추가 신청을 승인합니다. 승인 시 새로운 테넌트가 생성되고, 신청자가 해당 테넌트에 연결됩니다.", + "operationId": "approveCompanyRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "신청 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "승인 완료", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "승인되었습니다." + }, + "data": { + "$ref": "#/components/schemas/CompanyRequest" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "잘못된 요청 (이미 처리됨 등)" + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + }, + "404": { + "description": "신청 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/companies/requests/{id}/reject": { + "post": { + "tags": [ + "Companies" + ], + "summary": "회사 추가 신청 반려", + "description": "회사 추가 신청을 반려합니다.", + "operationId": "rejectCompanyRequest", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "신청 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "description": "반려 사유", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompanyRequestActionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "반려 완료", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "반려되었습니다." + }, + "data": { + "$ref": "#/components/schemas/CompanyRequest" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "잘못된 요청 (이미 처리됨 등)" + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + }, + "404": { + "description": "신청 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/companies/my-requests": { + "get": { + "tags": [ + "Companies" + ], + "summary": "내 회사 추가 신청 목록", + "description": "현재 사용자의 회사 추가 신청 목록을 조회합니다.", + "operationId": "getMyCompanyRequests", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "pending", + "approved", + "rejected" + ] + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "enum": [ + "created_at", + "company_name", + "status", + "processed_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "schema": { + "type": "integer", + "default": 20, + "maximum": 100, + "minimum": 1 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "minimum": 1 + } + } + ], + "responses": { + "200": { + "description": "내 신청 목록", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "$ref": "#/components/schemas/CompanyRequestPagination" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/comprehensive-analysis": { + "get": { + "tags": [ + "ComprehensiveAnalysis" + ], + "summary": "종합 분석 데이터 조회", + "description": "종합 경영 분석 데이터를 조회합니다. 오늘의 이슈, 예상 지출, 카드 관리, 접대비, 복리후생비, 미수금, 채권추심 현황을 포함합니다.", + "operationId": "getComprehensiveAnalysis", + "parameters": [ + { + "name": "date", + "in": "query", + "description": "기준 일자 (기본: 오늘)", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-26" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/ComprehensiveAnalysisData" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/construction/contracts": { + "get": { + "tags": [ + "Contract" + ], + "summary": "계약 목록 조회", + "operationId": "6e5cab5fda6ff15e3a2a72fcc09912d0", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "per_page", + "in": "query", + "schema": { + "type": "integer", + "example": 20 + } + }, + { + "name": "search", + "in": "query", + "description": "계약번호/현장명/거래처명 검색", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "pending", + "completed" + ] + } + }, + { + "name": "stage", + "in": "query", + "description": "단계 필터", + "schema": { + "type": "string", + "enum": [ + "estimate_selected", + "estimate_progress", + "delivery", + "installation", + "inspection", + "other" + ] + } + }, + { + "name": "partner_id", + "in": "query", + "description": "거래처 ID 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "contract_manager_id", + "in": "query", + "description": "계약담당자 ID 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "construction_pm_id", + "in": "query", + "description": "공사PM ID 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일 필터 (계약시작일 기준)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일 필터 (계약종료일 기준)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "is_active", + "in": "query", + "description": "활성화 상태 필터", + "schema": { + "type": "boolean" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "example": "created_at" + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "example": "desc" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ContractPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Contract" + ], + "summary": "계약 등록", + "operationId": "325df7c8e6f90b4afcc5ad991cf4d06d", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContractCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Contract" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/construction/contracts/{id}": { + "get": { + "tags": [ + "Contract" + ], + "summary": "계약 상세 조회", + "operationId": "0c5564fb6936f2345ac4e3e5effd1a02", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Contract" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Contract" + ], + "summary": "계약 수정", + "operationId": "b19d17de2930e39058f22943994852b6", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContractUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Contract" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Contract" + ], + "summary": "계약 삭제", + "operationId": "ca1172403ac126368e4f5657a824faa5", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/construction/contracts/bulk": { + "delete": { + "tags": [ + "Contract" + ], + "summary": "계약 일괄 삭제", + "operationId": "0e1a6c0466fd48ef1bb0bb216985ec70", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "ids": { + "description": "삭제할 계약 ID 목록", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/construction/contracts/stats": { + "get": { + "tags": [ + "Contract" + ], + "summary": "계약 통계 조회", + "description": "전체 계약 수, 상태별 수, 총 계약금액, 총 개소수 등의 통계 정보를 반환합니다.", + "operationId": "949598937995996461d0d7a7d0ab7e35", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "시작일 필터", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일 필터", + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ContractStats" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/construction/contracts/stage-counts": { + "get": { + "tags": [ + "Contract" + ], + "summary": "계약 단계별 카운트 조회", + "description": "각 단계별 계약 수를 반환합니다.", + "operationId": "ea4cf5efe53c1aa10534591b7b38e732", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "시작일 필터", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일 필터", + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ContractStageCounts" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/construction/contracts/from-bidding/{biddingId}": { + "post": { + "tags": [ + "Contract" + ], + "summary": "입찰에서 계약 생성 (낙찰 → 계약 전환)", + "description": "낙찰(awarded) 상태의 입찰을 계약으로 전환합니다. 계약번호는 CTR-YYYY-NNN 형식으로 자동 생성됩니다. 요청 본문의 필드는 모두 선택이며, 미입력시 입찰 데이터에서 자동으로 매핑됩니다.", + "operationId": "b10dcaeb8f5836c6b2a01f761eb8a01b", + "parameters": [ + { + "name": "biddingId", + "in": "path", + "description": "입찰 ID", + "required": true, + "schema": { + "type": "integer", + "example": 11 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContractFromBiddingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "계약 생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Contract" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "입찰을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "이미 계약이 등록된 입찰", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "낙찰 상태가 아닌 입찰", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/daily-report/note-receivables": { + "get": { + "tags": [ + "DailyReport" + ], + "summary": "어음 및 외상매출채권 현황 조회", + "description": "수취어음 현황을 조회합니다.", + "operationId": "getDailyReportNoteReceivables", + "parameters": [ + { + "name": "date", + "in": "query", + "description": "조회 일자 (기본: 오늘)", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-26" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NoteReceivableItem" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/daily-report/daily-accounts": { + "get": { + "tags": [ + "DailyReport" + ], + "summary": "일별 계좌 현황 조회", + "description": "일별 계좌별 수입/지출 현황을 조회합니다.", + "operationId": "getDailyReportDailyAccounts", + "parameters": [ + { + "name": "date", + "in": "query", + "description": "조회 일자 (기본: 오늘)", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-26" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DailyAccountItem" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/daily-report/summary": { + "get": { + "tags": [ + "DailyReport" + ], + "summary": "일일 보고서 요약", + "description": "일일 자금 현황 요약 통계를 조회합니다.", + "operationId": "getDailyReportSummary", + "parameters": [ + { + "name": "date", + "in": "query", + "description": "조회 일자 (기본: 오늘)", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-26" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/DailyReportSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/dashboard/summary": { + "get": { + "tags": [ + "Dashboard" + ], + "summary": "대시보드 요약 데이터 조회", + "description": "오늘 현황, 재무 요약, 매출/매입 요약, 할 일 요약을 반환합니다.", + "operationId": "getDashboardSummary", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/DashboardSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/dashboard/charts": { + "get": { + "tags": [ + "Dashboard" + ], + "summary": "대시보드 차트 데이터 조회", + "description": "입금/출금 추이, 거래처별 매출 차트 데이터를 반환합니다.", + "operationId": "getDashboardCharts", + "parameters": [ + { + "name": "period", + "in": "query", + "description": "조회 기간 (week: 7일, month: 30일, quarter: 3개월)", + "required": false, + "schema": { + "type": "string", + "default": "month", + "enum": [ + "week", + "month", + "quarter" + ] + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/DashboardCharts" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검사 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/dashboard/approvals": { + "get": { + "tags": [ + "Dashboard" + ], + "summary": "결재 현황 조회", + "description": "결재 대기 문서(결재함)와 내가 기안한 진행중인 문서 목록을 반환합니다.", + "operationId": "getDashboardApprovals", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "각 목록의 최대 항목 수 (1~50)", + "required": false, + "schema": { + "type": "integer", + "default": 10, + "maximum": 50, + "minimum": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/DashboardApprovals" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검사 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/departments": { + "get": { + "tags": [ + "Department" + ], + "summary": "부서 목록 조회", + "description": "테넌트 범위 내 부서 목록을 페이징으로 반환합니다. (q로 이름/코드 검색)", + "operationId": "2815f1ebbb4e4342d42ee38fb9be99d1", + "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 10 + } + }, + { + "name": "q", + "in": "query", + "required": false, + "schema": { + "type": "string", + "example": "운영" + } + }, + { + "name": "is_active", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "부서 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 목록 조회 성공" }, "data": { "properties": { @@ -177,137 +17096,5838 @@ "type": "integer", "example": 1 }, + "per_page": { + "type": "integer", + "example": 10 + }, + "total": { + "type": "integer", + "example": 2 + }, "data": { - "type": "array", - "items": { - "properties": { - "id": { - "type": "integer", - "example": 1 - }, - "user_id": { - "type": "string", - "example": "hamss" - }, - "phone": { - "type": "string", - "example": "010-4820-9104" - }, - "options": { - "type": "string", - "example": null, - "nullable": true - }, - "name": { - "type": "string", - "example": "권혁성" - }, - "email": { - "type": "string", - "example": "shine1324@gmail.com" - }, - "email_verified_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true - }, - "last_login_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true - }, - "current_team_id": { - "type": "integer", - "example": null, - "nullable": true - }, - "profile_photo_path": { - "type": "string", - "example": null, - "nullable": true - }, - "created_at": { - "type": "string", - "format": "date-time", - "example": "2025-07-16 18:28:41" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "example": "2025-07-25 23:13:06" - }, - "deleted_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true - } + "$ref": "#/components/schemas/DepartmentList" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Department" + ], + "summary": "부서 생성", + "operationId": "7562894b3d471d1281a2ebe032dd2c8b", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DepartmentCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "부서 생성 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 생성 성공" + }, + "data": { + "$ref": "#/components/schemas/Department" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/departments/tree": { + "get": { + "tags": [ + "Department" + ], + "summary": "부서 트리 조회", + "description": "부서를 계층 구조(트리)로 조회합니다. with_users=1 시 각 부서의 소속 사용자도 포함됩니다.", + "operationId": "9ae13a0399f5e4cc2eaa3788aa5af983", + "parameters": [ + { + "name": "with_users", + "in": "query", + "description": "사용자 포함 여부", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 0 + } + } + ], + "responses": { + "200": { + "description": "부서 트리 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 트리 조회" + }, + "data": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "본사" + }, + "code": { + "type": "string", + "example": "HQ", + "nullable": true + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DepartmentBrief" + } + }, + "users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserBrief" }, - "type": "object" + "nullable": true } }, - "first_page_url": { - "type": "string", - "example": "http://api.sam.kr/api/v1/member/index?page=1" + "type": "object" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/departments/{id}": { + "get": { + "tags": [ + "Department" + ], + "summary": "부서 단건 조회", + "operationId": "20ead37634a5fab0b30fafb2b1cae703", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + } + ], + "responses": { + "200": { + "description": "부서 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 조회 성공" + }, + "data": { + "$ref": "#/components/schemas/Department" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Department" + ], + "summary": "부서 삭제(소프트)", + "operationId": "ed1688eeef449c1801c4991417f4ce10", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + } + ], + "responses": { + "200": { + "description": "부서 삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 삭제 성공" + }, + "data": { + "properties": { + "id": { + "type": "integer", + "example": 7 }, - "from": { + "deleted_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-21 11:00:00" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Department" + ], + "summary": "부서 수정", + "operationId": "72359452b1ac47f10389ceed978df17a", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DepartmentUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "부서 수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 수정 성공" + }, + "data": { + "$ref": "#/components/schemas/Department" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/departments/{id}/users": { + "get": { + "tags": [ + "Department" + ], + "summary": "부서 사용자 목록", + "description": "해당 부서에 속한 사용자 목록을 페이징으로 반환합니다.", + "operationId": "6c8d0983ae3e653d98cba4d4188128df", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 20 + } + } + ], + "responses": { + "200": { + "description": "부서 사용자 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 사용자 목록 조회 성공" + }, + "data": { + "properties": { + "current_page": { "type": "integer", "example": 1 }, - "last_page": { - "type": "integer", - "example": 1 - }, - "last_page_url": { - "type": "string", - "example": "http://api.sam.kr/api/v1/member/index?page=1" - }, - "links": { - "type": "array", - "items": { - "properties": { - "url": { - "type": "string", - "example": null, - "nullable": true - }, - "label": { - "type": "string", - "example": "« Previous" - }, - "active": { - "type": "boolean", - "example": false - } - }, - "type": "object" - } - }, - "next_page_url": { - "type": "string", - "example": null, - "nullable": true - }, - "path": { - "type": "string", - "example": "http://api.sam.kr/api/v1/member/index" - }, "per_page": { "type": "integer", "example": 20 }, - "prev_page_url": { - "type": "string", - "example": null, - "nullable": true + "total": { + "type": "integer", + "example": 1 }, - "to": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserBrief" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Department" + ], + "summary": "부서 사용자 배정(단건)", + "operationId": "5d923a11765ccb6cb93f0b31f5b9c8c2", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DepartmentUserAttachRequest" + } + } + } + }, + "responses": { + "200": { + "description": "부서 사용자 배정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 사용자 배정 성공" + }, + "data": { + "properties": { + "department_id": { + "type": "integer", + "example": 7 + }, + "user_id": { + "type": "integer", + "example": 12 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "409": { + "description": "이미 배정됨", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "부서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/departments/{id}/users/{user}": { + "delete": { + "tags": [ + "Department" + ], + "summary": "부서 사용자 해제(단건)", + "operationId": "30f4ab61ae09998e682835b5bcc141f3", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + }, + { + "name": "user", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "responses": { + "200": { + "description": "부서 사용자 해제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 사용자 해제 성공" + }, + "data": { + "properties": { + "user_id": { + "type": "integer", + "example": 12 + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-21 11:00:00" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/departments/{id}/users/{user}/primary": { + "patch": { + "tags": [ + "Department" + ], + "summary": "주부서 설정/해제", + "operationId": "f4f0523282595d3b3c3f467ac929fdc2", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + }, + { + "name": "user", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "is_primary": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 1 + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "주부서 설정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "주부서 설정 성공" + }, + "data": { + "properties": { + "user_id": { + "type": "integer", + "example": 12 + }, + "department_id": { + "type": "integer", + "example": 7 + }, + "is_primary": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/departments/{id}/permissions": { + "get": { + "tags": [ + "Department" + ], + "summary": "부서 권한 목록", + "description": "부서에 설정된 ALLOW/DENY 목록을 조회합니다. (is_allowed=1|0, menu_id 필터 지원)", + "operationId": "7e9a95e39f02d3c3b5a5eaa17f18f416", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + }, + { + "name": "menu_id", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 101 + } + }, + { + "name": "is_allowed", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 1 + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "per_page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 20 + } + } + ], + "responses": { + "200": { + "description": "부서 권한 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 권한 목록 조회 성공" + }, + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { "type": "integer", "example": 3 }, - "total": { + "data": { + "type": "array", + "items": { + "properties": { + "permission_id": { + "type": "integer", + "example": 25 + }, + "permission_code": { + "type": "string", + "example": "menu.101.read" + }, + "is_allowed": { + "type": "integer", + "example": 1 + }, + "reason": { + "type": "string", + "example": "보안 이슈", + "nullable": true + }, + "effective_from": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "effective_to": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "부서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Department" + ], + "summary": "부서 권한 부여/차단(Upsert: 단건/배치)", + "description": "permission_id 기준으로 ALLOW(1) 또는 DENY(0) 처리합니다. 단건 또는 items 배열을 모두 지원합니다.", + "operationId": "95e1c346eaeec24d65fef8797ae9deea", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/DepartmentPermissionUpsertSingle" + }, + { + "$ref": "#/components/schemas/DepartmentPermissionUpsertMany" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "부서 권한 적용 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 권한 적용 성공" + }, + "data": { + "properties": { + "processed": { + "type": "integer", + "example": 2 + }, + "succeeded": { + "type": "integer", + "example": 2 + }, + "failed": { + "type": "array", + "items": { + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "부서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/departments/{id}/permissions/{permission}": { + "delete": { + "tags": [ + "Department" + ], + "summary": "부서 권한 해제", + "description": "지정 권한을 부서 매핑에서 제거합니다.", + "operationId": "a30ffbe8b5a81120999b6831153a5268", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "부서 ID", + "required": true, + "schema": { + "type": "integer", + "example": 7 + } + }, + { + "name": "permission", + "in": "path", + "description": "권한 ID", + "required": true, + "schema": { + "type": "integer", + "example": 15 + } + } + ], + "responses": { + "200": { + "description": "부서 권한 해제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "부서 권한 제거" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "부서 또는 권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/deposits": { + "get": { + "tags": [ + "Deposits" + ], + "summary": "입금 목록 조회", + "description": "입금 목록을 조회합니다.", + "operationId": "b21d566f227b836f2a5e4862e2963875", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (거래처명, 적요)", + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "payment_method", + "in": "query", + "description": "결제수단", + "schema": { + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ] + } + }, + { + "name": "bank_account_id", + "in": "query", + "description": "계좌 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "deposit_date", + "enum": [ + "deposit_date", + "amount", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Deposit" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Deposits" + ], + "summary": "입금 등록", + "description": "새로운 입금을 등록합니다.", + "operationId": "4a1a91f0d43f888b68d0801181cc3a18", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DepositCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Deposit" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/deposits/summary": { + "get": { + "tags": [ + "Deposits" + ], + "summary": "입금 요약 조회", + "description": "기간별 입금 요약을 조회합니다.", + "operationId": "770f20ea96ce20712c0c3c1d330ade75", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "payment_method", + "in": "query", + "description": "결제수단", + "schema": { + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ] + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/DepositSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/deposits/{id}": { + "get": { + "tags": [ + "Deposits" + ], + "summary": "입금 상세 조회", + "description": "입금 상세 정보를 조회합니다.", + "operationId": "1f54ad94db53152bf15c51e94a0baa35", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "입금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Deposit" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "입금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Deposits" + ], + "summary": "입금 수정", + "description": "입금 정보를 수정합니다.", + "operationId": "001bcd24971089738c3396ca421b2dee", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "입금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DepositUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Deposit" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "입금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Deposits" + ], + "summary": "입금 삭제", + "description": "입금을 삭제합니다. (Soft Delete)", + "operationId": "1635f9f115f7b448c64dc68fd61cff9e", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "입금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "입금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/bom-templates/{templateId}/diff": { + "get": { + "tags": [ + "Design BOM" + ], + "summary": "Diff two BOM templates", + "operationId": "a7b179391b9ba3403befd351bad8e3f6", + "parameters": [ + { + "name": "templateId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "other_template_id", + "in": "query", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "left_template_id": { + "type": "integer" + }, + "right_template_id": { + "type": "integer" + }, + "summary": { + "properties": { + "added": { + "type": "integer" + }, + "removed": { + "type": "integer" + }, + "changed": { + "type": "integer" + } + }, + "type": "object" + }, + "added": { + "type": "array", + "items": { + "properties": { + "ref_type": { + "type": "string", + "example": "MATERIAL" + }, + "ref_id": { + "type": "integer" + }, + "qty": { + "type": "number" + }, + "waste_rate": { + "type": "number" + }, + "uom_id": { + "type": "integer", + "nullable": true + }, + "notes": { + "type": "string", + "nullable": true + }, + "sort_order": { + "type": "integer" + } + }, + "type": "object" + } + }, + "removed": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DesignBomItemDiffRow" + } + }, + "changed": { + "type": "array", + "items": { + "properties": { + "ref_type": { + "type": "string" + }, + "ref_id": { + "type": "integer" + }, + "changes": { + "type": "object" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/bom-templates/{templateId}/clone": { + "post": { + "tags": [ + "Design BOM" + ], + "summary": "Clone a BOM template (deep copy)", + "operationId": "b1f631e18159485e9cc8ef385d36f176", + "parameters": [ + { + "name": "templateId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "target_version_id": { + "type": "integer", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "is_primary": { + "type": "boolean", + "nullable": true + }, + "notes": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Cloned", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "id": { + "type": "integer" + }, + "tenant_id": { + "type": "integer" + }, + "model_version_id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "is_primary": { + "type": "boolean" + }, + "notes": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/models": { + "get": { + "tags": [ + "Model" + ], + "summary": "모델 목록", + "description": "모델(설계 상위) 목록을 페이징으로 조회합니다.", + "operationId": "8ffe609126155eaa855e4b8c7417f717", + "parameters": [ + { + "name": "q", + "in": "query", + "description": "검색어(code/name/description like)", + "schema": { + "type": "string" + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/DesignModelPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Model" + ], + "summary": "모델 생성", + "description": "모델(설계 상위)을 생성합니다.", + "operationId": "2ff98bf9e947719a4b07a3f0dced9b98", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "code", + "name" + ], + "properties": { + "code": { + "type": "string", + "maxLength": 100, + "example": "KSS01" + }, + "name": { + "type": "string", + "maxLength": 200, + "example": "KSS 표준 모델" + }, + "category_id": { + "type": "integer", + "example": 12, + "nullable": true + }, + "lifecycle": { + "type": "string", + "example": "ACTIVE", + "nullable": true + }, + "description": { + "type": "string", + "example": "롤러 구조 표준 설계", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/DesignModel" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/models/{id}": { + "get": { + "tags": [ + "Model" + ], + "summary": "모델 상세", + "description": "단일 모델을 조회합니다. (versions 포함 가능)", + "operationId": "1a236f463efa60b83d34b3a453eb130f", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/DesignModel" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Model" + ], + "summary": "모델 수정", + "operationId": "facd823622efdc5d089619015ca75540", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "code": { + "type": "string", + "maxLength": 100, + "example": "KSS01" + }, + "name": { + "type": "string", + "maxLength": 200, + "example": "KSS 표준 모델(개정)" + }, + "category_id": { + "type": "integer", + "example": 12, + "nullable": true + }, + "lifecycle": { + "type": "string", + "example": "ACTIVE", + "nullable": true + }, + "description": { + "type": "string", + "example": "개정 메모", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Model" + ], + "summary": "모델 삭제(soft)", + "operationId": "0e62d61d15adc9503e83cd7baa6dd3d8", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/models/{modelId}/versions": { + "get": { + "tags": [ + "ModelVersion" + ], + "summary": "모델의 버전 목록", + "operationId": "8a2eb9c9477cec8796a8bcf3d34d09a0", + "parameters": [ + { + "name": "modelId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelVersion" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ModelVersion" + ], + "summary": "버전 DRAFT 생성", + "description": "version_no 미지정 시 자동 증가", + "operationId": "b79d40b95a3641ade7f5bc720d25718e", + "parameters": [ + { + "name": "modelId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "version_no": { + "type": "integer", + "example": 1, + "nullable": true + }, + "notes": { + "type": "string", + "example": "초안 메모", + "nullable": true + }, + "effective_from": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "effective_to": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ModelVersion" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/versions/{versionId}/release": { + "post": { + "tags": [ + "ModelVersion" + ], + "summary": "버전 RELEASED 전환", + "operationId": "a88d334173078711f089d3cd42c20cfa", + "parameters": [ + { + "name": "versionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "전환 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ModelVersion" + } + }, + "type": "object" + } + ] + } + } + } + }, + "409": { + "description": "상태 충돌", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/versions/{versionId}/bom-templates": { + "get": { + "tags": [ + "BomTemplate" + ], + "summary": "모델버전의 BOM 템플릿 목록", + "operationId": "ff0bfa1c632ba93f57891e92796220ef", + "parameters": [ + { + "name": "versionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BomTemplate" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "BomTemplate" + ], + "summary": "BOM 템플릿 upsert (name 기준)", + "description": "is_primary=true 지정 시 동일 모델버전의 기존 대표 템플릿은 자동 해제", + "operationId": "4d27e80e65ef309e3d7fd082c2f5f855", + "parameters": [ + { + "name": "versionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "name": { + "type": "string", + "maxLength": 100, + "example": "Main" + }, + "is_primary": { + "type": "boolean", + "example": true + }, + "notes": { + "type": "string", + "example": "표준 템플릿", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "저장 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BomTemplate" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/bom-templates/{templateId}": { + "get": { + "tags": [ + "BomTemplate" + ], + "summary": "BOM 템플릿 상세 (항목 포함)", + "operationId": "c015500cde3ea9b1ded61911c4d74d6b", + "parameters": [ + { + "name": "templateId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BomTemplate" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/design/bom-templates/{templateId}/items": { + "put": { + "tags": [ + "BomTemplate" + ], + "summary": "BOM 항목 일괄 치환", + "description": "기존 항목을 모두 삭제 후 본문 items로 재삽입", + "operationId": "a85263fcb82f3c45c9fe61d91be2ff17", + "parameters": [ + { + "name": "templateId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BomTemplateItemReplaceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "저장 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/documents": { + "get": { + "tags": [ + "Documents" + ], + "summary": "문서 목록 조회", + "description": "필터/검색/페이지네이션으로 문서 목록을 조회합니다.", + "operationId": "cf9c74d21c4f3809880f79e0a9ec06b4", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "DRAFT", + "PENDING", + "APPROVED", + "REJECTED", + "CANCELLED" + ] + } + }, + { + "name": "template_id", + "in": "query", + "description": "템플릿 ID 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (문서번호, 제목)", + "schema": { + "type": "string" + } + }, + { + "name": "from_date", + "in": "query", + "description": "시작일 이후", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "to_date", + "in": "query", + "description": "종료일 이전", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "created_at", + "document_no", + "title", + "status", + "submitted_at", + "completed_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Document" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Documents" + ], + "summary": "문서 생성", + "description": "템플릿 기반으로 새 문서를 생성합니다. 결재선, 데이터, 첨부파일을 함께 저장할 수 있습니다.", + "operationId": "e5003a991c606c25682fd001659f0b7f", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Document" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/documents/{id}": { + "get": { + "tags": [ + "Documents" + ], + "summary": "문서 상세 조회", + "description": "ID 기준 문서 상세 정보를 조회합니다. 템플릿, 결재선, 데이터, 첨부파일 포함.", + "operationId": "e862f269db4be29571e2846486469210", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Document" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Documents" + ], + "summary": "문서 삭제", + "description": "DRAFT 상태의 문서만 삭제 가능합니다 (소프트 삭제).", + "operationId": "05a8c48ec9609309456cb4dd1f30b247", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제되었습니다." + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "잘못된 요청 (삭제 불가 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Documents" + ], + "summary": "문서 수정", + "description": "DRAFT 또는 REJECTED 상태의 문서만 수정 가능합니다. REJECTED 상태에서 수정하면 DRAFT로 변경됩니다.", + "operationId": "b01ce033fdfb4993a19f1ba037434369", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "문서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Document" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (수정 불가 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "문서를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/employees": { + "get": { + "tags": [ + "Employees" + ], + "summary": "사원 목록 조회", + "description": "필터/검색/페이지네이션으로 사원 목록을 조회합니다.", + "operationId": "10df01073b4c4295c738e34aecadc888", + "parameters": [ + { + "name": "q", + "in": "query", + "description": "이름/이메일/사원번호 검색어", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "고용상태 필터", + "schema": { + "type": "string", + "enum": [ + "active", + "leave", + "resigned" + ] + } + }, + { + "name": "department_id", + "in": "query", + "description": "부서 ID 필터", + "schema": { + "type": "integer", + "example": 5 + } + }, + { + "name": "has_account", + "in": "query", + "description": "시스템 계정 보유 여부", + "schema": { + "type": "string", + "enum": [ + "0", + "1", + "true", + "false" + ] + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "created_at", + "name", + "employee_status", + "department_id" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Employee" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/employees?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 8 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/employees?page=8" + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/employees?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/employees" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 150 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Employees" + ], + "summary": "사원 등록", + "description": "새 사원을 등록합니다. password를 입력하면 시스템 계정도 함께 생성됩니다.", + "operationId": "a58c31a6c5f96bfbaf1edefcf3613484", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmployeeCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Employee" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "이메일 중복", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/employees/stats": { + "get": { + "tags": [ + "Employees" + ], + "summary": "사원 통계 조회", + "description": "사원 현황 통계를 조회합니다.", + "operationId": "6bd50dca39136cabbb8b749dc9c7d09a", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/EmployeeStats" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/employees/{id}": { + "get": { + "tags": [ + "Employees" + ], + "summary": "사원 상세 조회", + "description": "ID 기준 사원 상세 정보를 조회합니다.", + "operationId": "74b1c4cc4f612ba553ebd7b18020944d", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "사원 프로필 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Employee" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "사원을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Employees" + ], + "summary": "사원 삭제 (퇴직 처리)", + "description": "사원을 퇴직 처리합니다. employee_status가 'resigned'로 변경되고 소프트 삭제됩니다.", + "operationId": "b649c17a689018531f98753eecf10599", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "사원 프로필 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제 완료" + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "사원을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Employees" + ], + "summary": "사원 수정", + "description": "사원 정보를 수정합니다.", + "operationId": "25d50a1676dac0e6b232eaa2a9d369ee", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "사원 프로필 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmployeeUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Employee" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "사원을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "이메일 중복", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/employees/bulk-delete": { + "post": { + "tags": [ + "Employees" + ], + "summary": "사원 일괄 삭제", + "description": "여러 사원을 일괄 퇴직 처리합니다.", + "operationId": "f533a371fe69c1f044e151bb95abbb44", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "ids" + ], + "properties": { + "ids": { + "description": "삭제할 사원 ID 목록", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "일괄 삭제 완료" + }, + "data": { + "properties": { + "deleted_count": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/employees/{id}/create-account": { + "post": { + "tags": [ + "Employees" + ], + "summary": "시스템 계정 생성", + "description": "기존 사원에게 시스템 로그인 계정을 생성합니다.", + "operationId": "d2c42eea7f5162fb926b8c34a52ffc30", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "사원 프로필 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "password" + ], + "properties": { + "password": { + "description": "계정 비밀번호", + "type": "string", + "minLength": 8, + "example": "Password123!" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "계정 생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Employee" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "사원을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "이미 계정이 존재함", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/entertainment/summary": { + "get": { + "tags": [ + "Entertainment" + ], + "summary": "접대비 현황 요약 조회", + "description": "CEO 대시보드용 접대비 현황 요약 데이터를 조회합니다. 매출액, 한도, 사용금액, 잔여한도를 포함합니다.", + "operationId": "getEntertainmentSummary", + "parameters": [ + { + "name": "limit_type", + "in": "query", + "description": "기간 타입 (annual: 연간, quarterly: 분기)", + "required": false, + "schema": { + "type": "string", + "default": "quarterly", + "enum": [ + "annual", + "quarterly" + ] + } + }, + { + "name": "company_type", + "in": "query", + "description": "기업 유형 (large: 대기업, medium: 중견기업, small: 중소기업)", + "required": false, + "schema": { + "type": "string", + "default": "medium", + "enum": [ + "large", + "medium", + "small" + ] + } + }, + { + "name": "year", + "in": "query", + "description": "연도 (기본: 현재 연도)", + "required": false, + "schema": { + "type": "integer", + "example": 2026 + } + }, + { + "name": "quarter", + "in": "query", + "description": "분기 번호 (1-4, 기본: 현재 분기)", + "required": false, + "schema": { + "type": "integer", + "maximum": 4, + "minimum": 1, + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "$ref": "#/components/schemas/EntertainmentSummaryResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{pageId}/link-section": { + "post": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "페이지에 섹션 연결", + "description": "페이지와 섹션을 연결합니다.", + "operationId": "48dca9099946d924576463800114ae62", + "parameters": [ + { + "name": "pageId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LinkEntityRequest" + } + } + } + }, + "responses": { + "200": { + "description": "연결 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "연결 성공" + }, + "data": { + "$ref": "#/components/schemas/EntityRelationship" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "페이지 또는 섹션을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{pageId}/unlink-section/{sectionId}": { + "delete": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "페이지에서 섹션 연결 해제", + "description": "페이지와 섹션의 연결을 해제합니다.", + "operationId": "7c63ffea39be6614006a573451e866d5", + "parameters": [ + { + "name": "pageId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "연결 해제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "연결 해제 성공" + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{pageId}/link-field": { + "post": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "페이지에 필드 직접 연결", + "description": "페이지와 필드를 직접 연결합니다 (섹션 없이).", + "operationId": "22124c102e20f98c2f1c9a9309024ffe", + "parameters": [ + { + "name": "pageId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LinkEntityRequest" + } + } + } + }, + "responses": { + "200": { + "description": "연결 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "연결 성공" + }, + "data": { + "$ref": "#/components/schemas/EntityRelationship" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "페이지 또는 필드를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{pageId}/unlink-field/{fieldId}": { + "delete": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "페이지에서 필드 연결 해제", + "description": "페이지와 필드의 연결을 해제합니다.", + "operationId": "576518a664d6bf82d7d0f4dfeffb1d3c", + "parameters": [ + { + "name": "pageId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "fieldId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "연결 해제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "연결 해제 성공" + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{pageId}/relationships": { + "get": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "페이지의 모든 관계 조회", + "description": "페이지에 연결된 모든 관계(섹션, 필드)를 조회합니다.", + "operationId": "674831e04d3fe76231ffac4928449ee6", + "parameters": [ + { + "name": "pageId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EntityRelationship" + } + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "페이지를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{pageId}/structure": { + "get": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "페이지 구조 조회", + "description": "페이지의 전체 구조를 조회합니다 (섹션, 직접 연결된 필드, 중첩 구조).", + "operationId": "416dcd133e8a85b3b699f363eaa459e5", + "parameters": [ + { + "name": "pageId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "$ref": "#/components/schemas/PageStructure" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "페이지를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{sectionId}/link-field": { + "post": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "섹션에 필드 연결", + "description": "섹션과 필드를 연결합니다.", + "operationId": "91766abe9e5b59344428a96eb9d61b9e", + "parameters": [ + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LinkEntityRequest" + } + } + } + }, + "responses": { + "200": { + "description": "연결 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "연결 성공" + }, + "data": { + "$ref": "#/components/schemas/EntityRelationship" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "섹션 또는 필드를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{sectionId}/unlink-field/{fieldId}": { + "delete": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "섹션에서 필드 연결 해제", + "description": "섹션과 필드의 연결을 해제합니다.", + "operationId": "3a9ca920fa0eb3141edcae637e4f2d23", + "parameters": [ + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "fieldId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "연결 해제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "연결 해제 성공" + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{sectionId}/link-bom": { + "post": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "섹션에 BOM 항목 연결", + "description": "섹션과 BOM 항목을 연결합니다.", + "operationId": "94d483bc12937d6f326a95eeabb09f74", + "parameters": [ + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LinkEntityRequest" + } + } + } + }, + "responses": { + "200": { + "description": "연결 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "연결 성공" + }, + "data": { + "$ref": "#/components/schemas/EntityRelationship" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "섹션 또는 BOM 항목을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{sectionId}/unlink-bom/{bomId}": { + "delete": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "섹션에서 BOM 항목 연결 해제", + "description": "섹션과 BOM 항목의 연결을 해제합니다.", + "operationId": "5c8919e511bc8649adc8cba72985ce4e", + "parameters": [ + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "bomId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "연결 해제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "연결 해제 성공" + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{sectionId}/relationships": { + "get": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "섹션의 자식 관계 조회", + "description": "섹션에 연결된 모든 자식 관계(필드, BOM)를 조회합니다.", + "operationId": "651e4dc70a7700e0d0698845b613a8e3", + "parameters": [ + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EntityRelationship" + } + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "섹션을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/relationships/reorder": { + "post": { + "tags": [ + "ItemMaster-Relationships" + ], + "summary": "관계 순서 변경", + "description": "특정 부모 아래의 자식 관계 순서를 변경합니다.", + "operationId": "8b736f2fe59d636398c64b58093fb88d", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderRelationshipsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "순서 변경 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "정렬 변경 성공" + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/estimates": { + "get": { + "tags": [ + "Estimate" + ], + "summary": "견적 목록 조회", + "operationId": "41008a35c7d3140c7bcbb5689552448e", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "견적 상태", + "schema": { + "type": "string" + } + }, + { + "name": "customer_name", + "in": "query", + "description": "고객명", + "schema": { + "type": "string" + } + }, + { + "name": "model_set_id", + "in": "query", + "description": "모델셋 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "date_from", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "date_to", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어", + "schema": { + "type": "string" + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목수", + "schema": { + "type": "integer", + "default": 20 + } + } + ], + "responses": { + "200": { + "description": "성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Estimate" + ], + "summary": "견적 생성", + "operationId": "52e0aa47cbd3fc17d0cf2d5f5a8af529", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EstimateCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/estimates/{id}": { + "get": { + "tags": [ + "Estimate" + ], + "summary": "견적 상세 조회", + "operationId": "bcdbc98f75022ce3c7df50019cd304d8", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "견적 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Estimate" + ], + "summary": "견적 수정", + "operationId": "160fe8d2f779c8be406a243f927cf5dc", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "견적 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EstimateUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Estimate" + ], + "summary": "견적 삭제", + "operationId": "34ef3f71696ca6a56d197a78db5245c8", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "견적 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/estimates/{id}/clone": { + "post": { + "tags": [ + "Estimate" + ], + "summary": "견적 복제", + "operationId": "5be3478b21b639437c25906e53bf40e9", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "견적 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "estimate_name" + ], + "properties": { + "estimate_name": { + "description": "새 견적명", + "type": "string" + }, + "customer_name": { + "description": "고객명", + "type": "string" + }, + "project_name": { + "description": "프로젝트명", + "type": "string" + }, + "notes": { + "description": "비고", + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "복제 성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/estimates/{id}/status": { + "put": { + "tags": [ + "Estimate" + ], + "summary": "견적 상태 변경", + "operationId": "c7064bbbd79961e62e72802584eee51c", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "견적 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "status" + ], + "properties": { + "status": { + "description": "변경할 상태", + "type": "string", + "enum": [ + "DRAFT", + "SENT", + "APPROVED", + "REJECTED", + "EXPIRED" + ] + }, + "notes": { + "description": "상태 변경 사유", + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "상태 변경 성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/estimates/form-schema/{model_set_id}": { + "get": { + "tags": [ + "Estimate" + ], + "summary": "견적 폼 스키마 조회", + "operationId": "5a323c52daad737057fc8ba27af81e89", + "parameters": [ + { + "name": "model_set_id", + "in": "path", + "description": "모델셋 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/estimates/preview/{model_set_id}": { + "post": { + "tags": [ + "Estimate" + ], + "summary": "견적 계산 미리보기", + "operationId": "364d699669778acdd65be40938b7b935", + "parameters": [ + { + "name": "model_set_id", + "in": "path", + "description": "모델셋 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "parameters" + ], + "properties": { + "parameters": { + "description": "견적 파라미터", + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "계산 성공" + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/expected-expenses": { + "get": { + "tags": [ + "ExpectedExpense" + ], + "summary": "미지급비용 목록 조회", + "operationId": "7d268dc858d5f9c73f74e141dcf709d6", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (거래처명, 계정과목, 적요)", + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "transaction_type", + "in": "query", + "description": "거래유형", + "schema": { + "type": "string" + } + }, + { + "name": "payment_status", + "in": "query", + "description": "지급상태", + "schema": { + "type": "string" + } + }, + { + "name": "approval_status", + "in": "query", + "description": "결재상태", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "expected_payment_date" + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "asc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "schema": { + "type": "integer", + "default": 50 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/ExpectedExpensePagination" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ExpectedExpense" + ], + "summary": "미지급비용 등록", + "operationId": "3d8a94821dfd343ee704178f258aa051", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpectedExpenseCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/ExpectedExpense" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ExpectedExpense" + ], + "summary": "미지급비용 일괄 삭제", + "operationId": "57b5f5565f9e65e40bf6a9d6d20c24ae", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "deleted_count": { "type": "integer", "example": 3 } @@ -331,14 +22951,32377 @@ ] } }, - "/api/v1/member/show/{user_no}": { + "/api/v1/expected-expenses/{id}": { "get": { "tags": [ - "Member" + "ExpectedExpense" + ], + "summary": "미지급비용 상세 조회", + "operationId": "a699eb9cbaa42d64ade4af4b43c4e390", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "미지급비용 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/ExpectedExpense" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "ExpectedExpense" + ], + "summary": "미지급비용 수정", + "operationId": "d632b56cf6ddf88f3ff9c2af018d9987", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "미지급비용 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpectedExpenseUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/ExpectedExpense" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ExpectedExpense" + ], + "summary": "미지급비용 삭제", + "operationId": "31211fad8ff26795b8c1308ddadd5ffa", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "미지급비용 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/expected-expenses/update-payment-date": { + "put": { + "tags": [ + "ExpectedExpense" + ], + "summary": "예상 지급일 일괄 변경", + "operationId": "ae0435ad651d35070a693e60dbcd3f3d", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + }, + "expected_payment_date": { + "type": "string", + "format": "date", + "example": "2025-02-01" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 변경 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "updated_count": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/expected-expenses/summary": { + "get": { + "tags": [ + "ExpectedExpense" + ], + "summary": "미지급비용 요약 (기간별 합계)", + "operationId": "299c3fb60b9b19930ffa0540cbdb1605", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "payment_status", + "in": "query", + "description": "지급상태", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/ExpectedExpenseSummary" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/expected-expenses/dashboard-detail": { + "get": { + "tags": [ + "ExpectedExpense" + ], + "summary": "대시보드 상세 조회 (CEO 대시보드 당월 예상 지출내역 me4 모달용)", + "description": "당월 지출예상 요약, 상세 목록을 제공합니다. me4(지출예상) 모달에서 사용됩니다.", + "operationId": "03f8833c6e80b4bb4ee25f1c0e89dc6d", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/ExpectedExpenseDashboardDetail" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/options": { + "get": { + "tags": [ + "Tenant.Option Groups" + ], + "summary": "옵션 그룹 목록", + "description": "해당 테넌트의 옵션 그룹 목록을 페이징으로 반환합니다.", + "operationId": "9d8e526717916a9ea1b40560591bb53f", + "parameters": [ + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + }, + { + "name": "q", + "in": "query", + "description": "검색어(그룹키/이름)", + "required": false, + "schema": { + "type": "string", + "example": "position" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OptionGroup" + } + }, + "total": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Tenant.Option Groups" + ], + "summary": "옵션 그룹 생성", + "description": "옵션 그룹을 생성합니다.", + "operationId": "c01f31239824e40689cf67a99779d461", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptionGroupCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/OptionGroup" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/options/{id}": { + "get": { + "tags": [ + "Tenant.Option Groups" + ], + "summary": "옵션 그룹 단건 조회", + "operationId": "efb3ce6f14633fbf2fe6111ca1398b16", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/OptionGroup" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Tenant.Option Groups" + ], + "summary": "옵션 그룹 삭제", + "operationId": "5c63ca23c13600cc04b961038b879d8d", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "object", + "example": null, + "nullable": true + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Tenant.Option Groups" + ], + "summary": "옵션 그룹 수정", + "operationId": "3d7ebd14c84c796681f37c4732c6d0e9", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptionGroupUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/OptionGroup" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/options/{gid}/values": { + "get": { + "tags": [ + "Tenant.Option Values" + ], + "summary": "옵션 값 목록", + "operationId": "dfbce21dc071a24c20f0fa24beb52a47", + "parameters": [ + { + "name": "gid", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + }, + { + "name": "active_only", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "example": true + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OptionValue" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Tenant.Option Values" + ], + "summary": "옵션 값 생성", + "operationId": "2f7b08bd425116f76738b317403cae4d", + "parameters": [ + { + "name": "gid", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptionValueCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/OptionValue" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/options/{gid}/values/{id}": { + "get": { + "tags": [ + "Tenant.Option Values" + ], + "summary": "옵션 값 단건 조회", + "operationId": "ef4b0519992f7e02070c634fb7fca563", + "parameters": [ + { + "name": "gid", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 10 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/OptionValue" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Tenant.Option Values" + ], + "summary": "옵션 값 삭제", + "operationId": "6348546c3f25c9e9ff7c5cc2cfe7d0cb", + "parameters": [ + { + "name": "gid", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 10 + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "object", + "example": null, + "nullable": true + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Tenant.Option Values" + ], + "summary": "옵션 값 수정", + "operationId": "a8e5d4f612973441a0178b3422f55f6b", + "parameters": [ + { + "name": "gid", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 10 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptionValueUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/OptionValue" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/options/{gid}/values/reorder": { + "patch": { + "tags": [ + "Tenant.Option Values" + ], + "summary": "옵션 값 정렬 순서 일괄 변경", + "operationId": "cb8347f2e9d480f60a8507bd403dcb8e", + "parameters": [ + { + "name": "gid", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptionValueReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "object", + "example": { + "reordered": true + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/profiles": { + "get": { + "tags": [ + "Tenant.Profiles" + ], + "summary": "프로필 목록", + "description": "테넌트 내 회원 프로필 목록을 페이징으로 반환합니다.", + "operationId": "476c3d2b726569da6f77f0de2ea7a673", + "parameters": [ + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + }, + { + "name": "q", + "in": "query", + "description": "검색어(표기명/사번 등)", + "required": false, + "schema": { + "type": "string", + "example": "A-001" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ProfilePagination" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/profiles/{userId}": { + "get": { + "tags": [ + "Tenant.Profiles" + ], + "summary": "프로필 단건 조회", + "operationId": "cf3d51cda4411b0d6188634a9753faa9", + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 55 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Profile" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Tenant.Profiles" + ], + "summary": "프로필 수정(관리자)", + "description": "관리자 권한으로 해당 사용자의 프로필을 수정합니다. 테넌트에서 enabled된 필드만 반영됩니다.", + "operationId": "e7a5de51f1a997d079dd82f24dc5c3d0", + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 55 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProfileUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Profile" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/profiles/me": { + "get": { + "tags": [ + "Tenant.Profiles" + ], + "summary": "내 프로필 조회", + "operationId": "6cc3e3db4f45bac067f75364fed22123", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Profile" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Tenant.Profiles" + ], + "summary": "내 프로필 수정", + "operationId": "759f20b0d271d6b37b9ca354d842553f", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProfileUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Profile" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/upload": { + "post": { + "tags": [ + "Files" + ], + "summary": "파일 업로드", + "description": "파일을 임시 폴더에 업로드합니다. 이후 /files/move로 정식 폴더로 이동시켜야 합니다.", + "operationId": "15956f09c71ecf768ffad20470a26330", + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file" + ], + "properties": { + "file": { + "description": "업로드할 파일 (최대 20MB)", + "type": "string", + "format": "binary" + }, + "description": { + "type": "string", + "maxLength": 500, + "example": "계약서 원본", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "파일 업로드 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/File" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "용량 초과 또는 파일 형식 오류" + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/move": { + "post": { + "tags": [ + "Files" + ], + "summary": "파일 이동", + "description": "임시 폴더의 파일들을 정식 폴더로 이동하고 문서에 첨부합니다.", + "operationId": "f2f669da9a27bcdf27a7b8edf8111878", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "file_ids", + "folder_id" + ], + "properties": { + "file_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + }, + "folder_id": { + "description": "대상 폴더 ID", + "type": "integer", + "example": 1 + }, + "document_id": { + "description": "첨부할 문서 ID", + "type": "integer", + "example": 10, + "nullable": true + }, + "document_type": { + "description": "문서 타입", + "type": "string", + "maxLength": 100, + "example": "Order", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "파일 이동 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/File" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "파일 또는 폴더를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files": { + "get": { + "tags": [ + "Files" + ], + "summary": "파일 목록 조회", + "description": "폴더별, 문서별 파일 목록을 조회합니다.", + "operationId": "48125dcc4808454ca7354550e3347ce8", + "parameters": [ + { + "name": "folder_id", + "in": "query", + "description": "폴더 ID (선택)", + "schema": { + "type": "integer" + } + }, + { + "name": "document_id", + "in": "query", + "description": "문서 ID (선택)", + "schema": { + "type": "integer" + } + }, + { + "name": "document_type", + "in": "query", + "description": "문서 타입 (선택)", + "schema": { + "type": "string" + } + }, + { + "name": "is_temp", + "in": "query", + "description": "임시 파일만 조회", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "파일 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/File" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/{id}": { + "get": { + "tags": [ + "Files" + ], + "summary": "파일 상세 조회", + "description": "파일 ID로 상세 정보를 조회합니다.", + "operationId": "fa1cd525929fe962d8d9556ea1d0c46d", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "파일 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/File" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "파일을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Files" + ], + "summary": "파일 삭제", + "description": "파일을 휴지통으로 이동합니다 (복구 가능).", + "operationId": "e4fb52ed14024441cf2646cf325d5e1e", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "파일 삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "파일을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/trash": { + "get": { + "tags": [ + "Files" + ], + "summary": "휴지통 파일 목록", + "description": "삭제된 파일 목록을 조회합니다 (30일 보관).", + "operationId": "45b44cfedcc72c883900957a34e42c39", + "responses": { + "200": { + "description": "휴지통 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/File" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/{id}/download": { + "get": { + "tags": [ + "Files" + ], + "summary": "파일 다운로드", + "description": "파일을 다운로드합니다.", + "operationId": "26701c7179386b050ea1e4162e6267c2", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "파일 다운로드", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "파일을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/{id}/restore": { + "post": { + "tags": [ + "Files" + ], + "summary": "파일 복구", + "description": "휴지통의 파일을 복구합니다.", + "operationId": "0a8ab9996e47b2f1b79a3e5c0a602cb4", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "파일 복구 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/File" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "파일을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/{id}/permanent": { + "delete": { + "tags": [ + "Files" + ], + "summary": "파일 영구 삭제", + "description": "파일을 물리적으로 완전히 삭제합니다 (복구 불가).", + "operationId": "0588aa504ff8bf3246aca6fa09cd8421", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "파일 영구 삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "파일을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/{id}/share": { + "post": { + "tags": [ + "Files" + ], + "summary": "공유 링크 생성", + "description": "파일의 임시 공유 링크를 생성합니다 (기본 24시간).", + "operationId": "7cf156b4549a3f933af20c128ccee096", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "expiry_hours": { + "description": "만료 시간 (시간 단위, 최대 7일)", + "type": "integer", + "maximum": 168, + "minimum": 1, + "example": 24 + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "공유 링크 생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/FileShareLink" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "파일을 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/files/share/{token}": { + "get": { + "tags": [ + "Files" + ], + "summary": "공유 파일 다운로드", + "description": "공유 토큰으로 파일을 다운로드합니다 (인증 불필요).", + "operationId": "37997afde48a1e3e746d019586303cef", + "parameters": [ + { + "name": "token", + "in": "path", + "description": "64자 공유 토큰", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "파일 다운로드", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "토큰을 찾을 수 없음" + }, + "410": { + "description": "링크가 만료됨" + } + } + } + }, + "/api/v1/storage/usage": { + "get": { + "tags": [ + "Files" + ], + "summary": "저장소 사용량 조회", + "description": "현재 테넌트의 저장소 사용량 정보를 조회합니다.", + "operationId": "e495fc3e3312464932d88884d815032a", + "responses": { + "200": { + "description": "사용량 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/StorageUsage" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/folders": { + "get": { + "tags": [ + "Folder" + ], + "summary": "폴더 목록 조회", + "description": "테넌트의 모든 폴더를 display_order 순으로 조회합니다.", + "operationId": "07e6467df73cd06449b2f7195f3ab335", + "responses": { + "200": { + "description": "폴더 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Folder" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Folder" + ], + "summary": "폴더 생성", + "description": "새로운 폴더를 생성합니다.", + "operationId": "a01afc068b575eff51738b3bc8fd2fc3", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FolderStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "폴더 생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Folder" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "유효성 검증 실패" + }, + "409": { + "description": "중복된 folder_key" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/folders/{id}": { + "get": { + "tags": [ + "Folder" + ], + "summary": "폴더 상세 조회", + "description": "폴더 ID로 상세 정보를 조회합니다.", + "operationId": "2d992f1e4d009ff11ddf0a1b64d3ec7b", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "폴더 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "폴더 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Folder" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "폴더를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Folder" + ], + "summary": "폴더 수정", + "description": "폴더 정보를 수정합니다.", + "operationId": "83e85c775f38e7feddf0dd68927cefb1", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "폴더 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FolderUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "폴더 수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Folder" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "유효성 검증 실패" + }, + "404": { + "description": "폴더를 찾을 수 없음" + }, + "409": { + "description": "중복된 folder_key" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Folder" + ], + "summary": "폴더 삭제", + "description": "폴더를 비활성화합니다. 파일이 있는 폴더는 삭제할 수 없습니다.", + "operationId": "1672f3c37c31162dca8a45a45ec227c1", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "폴더 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "폴더 삭제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Folder" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "폴더에 파일이 있어 삭제 불가" + }, + "404": { + "description": "폴더를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/folders/reorder": { + "post": { + "tags": [ + "Folder" + ], + "summary": "폴더 순서 변경", + "description": "여러 폴더의 표시 순서를 일괄 변경합니다.", + "operationId": "8c96f716978a12bbc89ba25edbd1cd86", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FolderReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "순서 변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Folder" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "유효성 검증 실패" + }, + "404": { + "description": "일부 폴더를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/internal/exchange-token": { + "post": { + "tags": [ + "Internal" + ], + "summary": "토큰 교환", + "description": "MNG 서버에서 HMAC 서명된 페이로드로 API Sanctum 토큰을 발급받습니다. API Key 및 Bearer 인증이 필요하지 않습니다.", + "operationId": "ea989d2b870174f2834ab2766033bb23", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExchangeTokenRequest" + } + } + } + }, + "responses": { + "200": { + "description": "토큰 교환 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "토큰이 교환되었습니다." + }, + "data": { + "$ref": "#/components/schemas/ExchangeTokenResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패 (HMAC 서명 불일치 또는 만료)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v1/item-master/init": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "품목기준관리 초기 데이터 로드", + "operationId": "bac71b07461808225e98c7e674f81dae", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemMasterInitResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/fields": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "필드 목록 조회", + "description": "섹션과 연결되지 않은 필드 목록을 조회합니다.", + "operationId": "d364722fbdabcbb2a10db14859eaec3c", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemField" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "필드 생성", + "description": "섹션과 연결되지 않은 필드를 생성합니다.", + "operationId": "4d4da6a8766a3ce750145f222e8962c9", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndependentFieldStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemField" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{sectionId}/fields": { + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "필드 생성 (섹션 연결)", + "operationId": "83d3060e9cbb95a8d97abec5186b947a", + "parameters": [ + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemFieldStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemField" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/fields/{id}": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "필드 수정", + "operationId": "4ccbe0e6ca24108bcebded825b354df7", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemFieldUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemField" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ItemMaster" + ], + "summary": "필드 삭제", + "operationId": "5e06ce35200010a7cbb46e2aac55e272", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{sectionId}/fields/reorder": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "필드 순서 변경", + "operationId": "c3bb551af1388365ece7fff815c26273", + "parameters": [ + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "순서 변경 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/fields/{id}/clone": { + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "필드 복제", + "description": "기존 필드를 복제하여 새 필드를 생성합니다.", + "operationId": "8900f0ddcd0211141e9a61f0bff3f5ff", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "복제할 필드 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "복제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemField" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/fields/{id}/usage": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "필드 사용처 조회", + "description": "필드가 어떤 섹션/페이지에 연결되어 있는지 조회합니다.", + "operationId": "eaab4a5b74cf739787c21eb117fdaa8f", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "필드 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/FieldUsageResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/unit-options": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "단위 옵션 목록", + "operationId": "0a22268b06516a7b206dcdd0a6dc2526", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnitOption" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "단위 옵션 생성", + "operationId": "4cd5c6c6f8e8bc5a84ee471b685e2353", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnitOptionStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/UnitOption" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/unit-options/{id}": { + "delete": { + "tags": [ + "ItemMaster" + ], + "summary": "단위 옵션 삭제", + "operationId": "1e504d250f245d46248758213273b936", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "페이지 목록 조회", + "operationId": "9bf69bb84acd8e26b56e53ba6b7492ee", + "parameters": [ + { + "name": "item_type", + "in": "query", + "description": "품목 유형 필터", + "schema": { + "type": "string", + "enum": [ + "FG", + "PT", + "SM", + "RM", + "CS" + ] + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemPage" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "페이지 생성", + "operationId": "25d4bb71a0b3e707224a323f7d39665a", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemPageStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemPage" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{id}": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "페이지 수정", + "operationId": "20f8c5e5a569609ae9ab8dd2beb667fb", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemPageUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemPage" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ItemMaster" + ], + "summary": "페이지 삭제", + "description": "페이지를 삭제합니다. 연결된 섹션/필드는 삭제되지 않고 관계만 해제됩니다.", + "operationId": "b2b7e48ad196f0babe2adfa700e3bf56", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 목록 조회", + "description": "페이지와 연결되지 않은 섹션 목록을 조회합니다. is_template 파라미터로 템플릿 필터링이 가능합니다.", + "operationId": "08d9380295f0fb2e2b57a9a8ee30cf72", + "parameters": [ + { + "name": "is_template", + "in": "query", + "description": "템플릿 여부 필터", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSection" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 생성", + "description": "페이지와 연결되지 않은 섹션을 생성합니다.", + "operationId": "e9a3c4e287cb1de99d6e54d5be060227", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndependentSectionStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemSection" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{pageId}/sections": { + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 생성 (페이지 연결)", + "operationId": "4e303dc0abce6b529f0faab963aa25f6", + "parameters": [ + { + "name": "pageId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemSectionStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemSection" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{id}": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 수정", + "operationId": "37422493eabba29cd41df5722206bad5", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemSectionUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemSection" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 삭제", + "description": "섹션을 삭제합니다. 연결된 필드/BOM은 삭제되지 않고 관계만 해제됩니다.", + "operationId": "4b1be81cef9965746478b4b54d5f62a0", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/pages/{pageId}/sections/reorder": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 순서 변경", + "operationId": "e851440070ff5a49dfba3fe988a80604", + "parameters": [ + { + "name": "pageId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "순서 변경 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{id}/clone": { + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 복제", + "description": "기존 섹션을 복제하여 새 섹션을 생성합니다. 하위 필드와 BOM 항목도 함께 복제됩니다.", + "operationId": "b6be6c685d3601d37b7a6f32726712ea", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "복제할 섹션 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "복제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemSection" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{id}/usage": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 사용처 조회", + "description": "섹션이 어떤 페이지에 연결되어 있는지 조회합니다 (entity_relationships 기반).", + "operationId": "aa48e0fdd78ad6dc332fe50f6221a15c", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "섹션 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/SectionUsageResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/section-templates": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 템플릿 목록", + "operationId": "03b2b455382b4379e17a7e28348d7a2d", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SectionTemplate" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 템플릿 생성", + "operationId": "bfddc2f4851147a94517a0d2bf32e54c", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SectionTemplateStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/SectionTemplate" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/section-templates/{id}": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 템플릿 수정", + "operationId": "ff1ecf4fb31cdfd2ea3537c61d294e34", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SectionTemplateUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/SectionTemplate" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ItemMaster" + ], + "summary": "섹션 템플릿 삭제", + "operationId": "1de889107771a16661556ff7c48f76ce", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/bom-items": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "BOM 목록 조회", + "description": "섹션과 연결되지 않은 BOM 항목 목록을 조회합니다.", + "operationId": "688d30d831fb6336781498386aac284f", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemBomItem" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "BOM 생성", + "description": "섹션과 연결되지 않은 BOM 항목을 생성합니다.", + "operationId": "8b39d430c9ad64dc14f2987cf6b9898c", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndependentBomItemStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemBomItem" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/sections/{sectionId}/bom-items": { + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "BOM 항목 생성 (섹션 연결)", + "operationId": "145c317aff009dae56f0cbf591668c71", + "parameters": [ + { + "name": "sectionId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemBomItemStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemBomItem" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/bom-items/{id}": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "BOM 항목 수정", + "operationId": "75bf5bb4cd6c627fb65f273d83b689e4", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemBomItemUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ItemBomItem" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ItemMaster" + ], + "summary": "BOM 항목 삭제", + "operationId": "cadeb90e6dbd6dd3f910fb4570d375fa", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/custom-tabs": { + "get": { + "tags": [ + "ItemMaster" + ], + "summary": "커스텀 탭 목록", + "operationId": "f01f6efd55066496da2dade40890278c", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomTab" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ItemMaster" + ], + "summary": "커스텀 탭 생성", + "operationId": "f6ff7dc7dde8c6d8315f8e7f97ef2838", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomTabStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CustomTab" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/custom-tabs/{id}": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "커스텀 탭 수정", + "operationId": "087a05188b0dc53fb3dbe04999926f18", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomTabUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/CustomTab" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ItemMaster" + ], + "summary": "커스텀 탭 삭제", + "operationId": "ff0cf113ca7ba3ea5769b60b32eab3b8", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/item-master/custom-tabs/reorder": { + "put": { + "tags": [ + "ItemMaster" + ], + "summary": "커스텀 탭 순서 변경", + "operationId": "b848e157e4c6b942f49b963f758ff9d1", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "순서 변경 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items": { + "get": { + "tags": [ + "Items" + ], + "summary": "품목 목록 조회 (통합)", + "description": "Product + Material 통합 조회, 페이징 지원. type 또는 group_id 중 하나는 필수입니다.", + "operationId": "7eced92a2cc19d25613742bcb5dfc685", + "parameters": [ + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + }, + { + "name": "search", + "in": "query", + "description": "검색어 (code, name)", + "schema": { + "type": "string" + }, + "example": "P-001" + }, + { + "name": "type", + "in": "query", + "description": "품목 타입 (FG,PT,SM,RM,CS). type 또는 group_id 중 하나 필수", + "schema": { + "type": "string" + }, + "example": "FG" + }, + { + "name": "group_id", + "in": "query", + "description": "그룹 ID (1=품목). type 또는 group_id 중 하나 필수", + "schema": { + "type": "integer" + }, + "example": 1 + }, + { + "name": "category_id", + "in": "query", + "description": "카테고리 ID 필터", + "schema": { + "type": "integer" + }, + "example": 1 + }, + { + "name": "include_deleted", + "in": "query", + "description": "삭제된 항목 포함 여부", + "schema": { + "type": "boolean" + }, + "example": false + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Item" + } + }, + "meta": { + "$ref": "#/components/schemas/PaginationMeta" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Items" + ], + "summary": "품목 생성", + "description": "product_type에 따라 Product(FG,PT) 또는 Material(SM,RM,CS) 테이블에 저장됩니다.", + "operationId": "fa3cfc59d0ec4953c7d53a1f83b3962e", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "품목이 등록되었습니다." + }, + "data": { + "$ref": "#/components/schemas/Item" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/code/{code}": { + "get": { + "tags": [ + "Items" + ], + "summary": "품목 코드로 상세 조회", + "description": "Product 먼저 조회 후, 없으면 Material에서 조회합니다.", + "operationId": "197fe896c23c3460df823adf0c2850ae", + "parameters": [ + { + "name": "code", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "example": "P-001" + }, + { + "name": "include_bom", + "in": "query", + "description": "BOM 포함 여부 (Product만 해당)", + "schema": { + "type": "boolean" + }, + "example": false + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "품목을 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/Item" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "품목 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}": { + "get": { + "tags": [ + "Items" + ], + "summary": "품목 ID로 상세 조회", + "description": "item_type 파라미터로 조회할 테이블을 지정합니다. (FG,PT→products / SM,RM,CS→materials)", + "operationId": "269c6720bebb5e8193a378138ccd11ea", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + }, + { + "name": "item_type", + "in": "query", + "description": "품목 유형 (기본값: FG)", + "required": false, + "schema": { + "type": "string", + "default": "FG", + "enum": [ + "FG", + "PT", + "SM", + "RM", + "CS" + ] + }, + "example": "FG" + }, + { + "name": "include_price", + "in": "query", + "description": "단가 정보 포함 여부", + "schema": { + "type": "boolean" + }, + "example": false + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID (단가 조회 시)", + "schema": { + "type": "integer" + }, + "example": 1 + }, + { + "name": "price_date", + "in": "query", + "description": "단가 기준일", + "schema": { + "type": "string", + "format": "date" + }, + "example": "2025-01-10" + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "$ref": "#/components/schemas/Item" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "품목 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Items" + ], + "summary": "품목 수정", + "description": "item_type 필드 필수. Product(FG,PT) 또는 Material(SM,RM,CS)을 자동 분기하여 수정합니다.", + "operationId": "3945480870bcd8ab82f7e86e3d1a442a", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "품목이 수정되었습니다." + }, + "data": { + "$ref": "#/components/schemas/Item" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "코드 중복", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "품목 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Items" + ], + "summary": "품목 삭제", + "description": "item_type 파라미터로 삭제할 테이블을 지정합니다. BOM 구성품으로 사용 중인 경우 삭제 불가.", + "operationId": "aba97452a8c099ff314c380113c466ac", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + }, + { + "name": "item_type", + "in": "query", + "description": "품목 유형 (기본값: FG)", + "required": false, + "schema": { + "type": "string", + "default": "FG", + "enum": [ + "FG", + "PT", + "SM", + "RM", + "CS" + ] + }, + "example": "FG" + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "품목이 삭제되었습니다." + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "BOM 사용 중", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "품목 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/batch": { + "delete": { + "tags": [ + "Items" + ], + "summary": "품목 일괄 삭제", + "description": "item_type 필드 필수. 여러 품목을 한 번에 삭제합니다. BOM 구성품으로 사용 중인 경우 삭제 불가.", + "operationId": "0f4ac27ffb9564afaa967d1a7ed301a0", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemBatchDeleteRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "품목이 일괄 삭제되었습니다." + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "BOM 사용 중", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "품목 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/bom": { + "get": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 목록 조회 (flat list)", + "operationId": "1608c295359ac8ab794fe63b60b5b80c", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목 조회" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BOMLine" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 라인 추가 (bulk upsert)", + "operationId": "edecb8b9e29c263627f4f5cf145dcb3f", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BOMCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목이 등록되었습니다." + }, + "data": { + "properties": { + "created": { + "type": "integer", + "example": 3 + }, + "updated": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/bom/tree": { + "get": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 트리 구조 조회 (계층적)", + "operationId": "fe4379619c1d9c59ca27541fe0c03dc1", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + }, + { + "name": "depth", + "in": "query", + "description": "최대 깊이 (기본값: 10)", + "schema": { + "type": "integer" + }, + "example": 10 + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목 조회" + }, + "data": { + "$ref": "#/components/schemas/BOMTree" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/bom/{lineId}": { + "put": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 라인 수정", + "operationId": "c6411b2a8cc1c6b09b3a311452ca866d", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + }, + { + "name": "lineId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BOMUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목이 수정되었습니다." + }, + "data": { + "$ref": "#/components/schemas/BOMLine" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 라인 삭제", + "operationId": "609b516341e19536aee0a49244959e38", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + }, + { + "name": "lineId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목이 삭제되었습니다." + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/bom/summary": { + "get": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 요약 정보", + "operationId": "9c0dfdcec72e5b2a262afea027a98bce", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목 조회" + }, + "data": { + "properties": { + "count": { + "type": "integer", + "example": 10 + }, + "count_product": { + "type": "integer", + "example": 5 + }, + "count_material": { + "type": "integer", + "example": 5 + }, + "quantity_sum": { + "type": "string", + "example": "25.5000" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/bom/validate": { + "get": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 유효성 검사", + "operationId": "92e208a44df7bc25441195494bca1944", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목 조회" + }, + "data": { + "properties": { + "valid": { + "type": "boolean", + "example": true + }, + "errors": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "error": { + "type": "string", + "example": "INVALID_QUANTITY" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/bom/replace": { + "post": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 전체 교체 (기존 삭제 후 재등록)", + "operationId": "1ebe2fd42987ef9f876bf2365b8dd921", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "categories": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "name": { + "type": "string", + "example": "조립품" + }, + "items": { + "type": "array", + "items": { + "required": [ + "ref_type", + "ref_id", + "quantity" + ], + "properties": { + "ref_type": { + "type": "string", + "example": "PRODUCT" + }, + "ref_id": { + "type": "integer", + "example": 10 + }, + "quantity": { + "type": "number", + "example": 2.5 + }, + "sort_order": { + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목이 등록되었습니다." + }, + "data": { + "properties": { + "deleted_count": { + "type": "integer", + "example": 5 + }, + "inserted_count": { + "type": "integer", + "example": 8 + }, + "message": { + "type": "string", + "example": "BOM 저장 성공" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/bom/reorder": { + "post": { + "tags": [ + "Items BOM" + ], + "summary": "BOM 정렬 변경", + "operationId": "e3b5b4dea36f55b14215fc81ddd922dc", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "items": { + "type": "array", + "items": { + "required": [ + "id", + "sort_order" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 정렬이 변경되었습니다." + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/bom/categories": { + "get": { + "tags": [ + "Items BOM" + ], + "summary": "BOM에서 사용 중인 카테고리 목록", + "operationId": "9082acca3053d3c1ba34914a5a68f0bd", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 항목 조회" + }, + "data": { + "type": "array", + "items": { + "properties": { + "category_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "category_name": { + "type": "string", + "example": "조립품" + }, + "count": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/files": { + "get": { + "tags": [ + "Items Files" + ], + "summary": "품목 파일 목록 조회", + "description": "품목에 등록된 모든 파일을 field_key별로 그룹핑하여 조회합니다. 응답은 field_key를 키로 하고 파일 배열을 값으로 하는 객체입니다.", + "operationId": "getItemFiles", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer", + "example": 795 + } + }, + { + "name": "item_type", + "in": "query", + "description": "품목 유형 (FG|PT|SM|RM|CS)", + "required": false, + "schema": { + "type": "string", + "default": "FG", + "enum": [ + "FG", + "PT", + "SM", + "RM", + "CS" + ] + } + }, + { + "name": "field_key", + "in": "query", + "description": "특정 field_key만 조회 (미지정 시 전체)", + "required": false, + "schema": { + "type": "string", + "example": "drawing" + } + } + ], + "responses": { + "200": { + "description": "파일 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "$ref": "#/components/schemas/ItemFilesGrouped" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "품목 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Items Files" + ], + "summary": "품목 파일 업로드", + "description": "품목에 파일을 업로드합니다.\n *\n * **동작 방식**:\n * - `file_id` 없음 → 새 파일 추가\n * - `file_id` 있음 → 기존 파일 soft delete 후 새 파일 추가 (교체)\n *\n * **저장 경로**: `storage/app/tenants/{tenant_id}/items/{year}/{month}/{stored_name}`", + "operationId": "uploadItemFile", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer", + "example": 795 + } + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "field_key", + "file" + ], + "properties": { + "field_key": { + "description": "필드 키 (자유롭게 지정)", + "type": "string", + "example": "drawing" + }, + "file": { + "description": "업로드할 파일 (이미지: jpg,png,gif,svg / 문서: pdf,doc,docx,xls,xlsx,hwp). 최대 20MB", + "type": "string", + "format": "binary" + }, + "file_id": { + "description": "기존 파일 ID (있으면 교체, 없으면 추가)", + "type": "integer", + "example": 123, + "nullable": true + }, + "item_type": { + "description": "품목 유형 (FG|PT|SM|RM|CS)", + "type": "string", + "example": "FG" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "파일 업로드 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "파일이 업로드되었습니다." + }, + "data": { + "$ref": "#/components/schemas/ItemFileUploadResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "품목 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/items/{id}/files/{fileId}": { + "delete": { + "tags": [ + "Items Files" + ], + "summary": "품목 파일 삭제", + "description": "품목의 특정 파일을 삭제합니다 (Soft Delete).", + "operationId": "deleteItemFile", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "품목 ID", + "required": true, + "schema": { + "type": "integer", + "example": 795 + } + }, + { + "name": "fileId", + "in": "path", + "description": "파일 ID", + "required": true, + "schema": { + "type": "integer", + "example": 123 + } + }, + { + "name": "item_type", + "in": "query", + "description": "품목 유형 (FG|PT|SM|RM|CS)", + "required": false, + "schema": { + "type": "string", + "default": "FG", + "enum": [ + "FG", + "PT", + "SM", + "RM", + "CS" + ] + } + } + ], + "responses": { + "200": { + "description": "파일 삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "파일이 삭제되었습니다." + }, + "data": { + "$ref": "#/components/schemas/ItemFileDeleteResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "품목 또는 파일 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/leaves": { + "get": { + "tags": [ + "Leaves" + ], + "summary": "휴가 목록 조회", + "description": "필터/검색/페이지네이션으로 휴가 목록을 조회합니다.", + "operationId": "d63fadf1fa3008683b1f28a6d7ac69e5", + "parameters": [ + { + "name": "user_id", + "in": "query", + "description": "사용자 ID 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "pending", + "approved", + "rejected", + "cancelled" + ] + } + }, + { + "name": "leave_type", + "in": "query", + "description": "휴가 유형 필터", + "schema": { + "type": "string", + "enum": [ + "annual", + "half_am", + "half_pm", + "sick", + "family", + "maternity", + "parental" + ] + } + }, + { + "name": "date_from", + "in": "query", + "description": "시작일 이후", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "date_to", + "in": "query", + "description": "종료일 이전", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "year", + "in": "query", + "description": "연도 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "start_date", + "enum": [ + "start_date", + "created_at", + "status" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Leave" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Leaves" + ], + "summary": "휴가 신청", + "description": "새 휴가를 신청합니다. 잔여일수를 초과하거나 기간이 중복되면 실패합니다.", + "operationId": "535b669d739ce8bbb34365cdba5c18cc", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LeaveCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "신청 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Leave" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (잔여일수 부족, 기간 중복 등)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/leaves/{id}": { + "get": { + "tags": [ + "Leaves" + ], + "summary": "휴가 상세 조회", + "description": "ID 기준 휴가 상세 정보를 조회합니다.", + "operationId": "17d665f5c20e3586da106b2ba05580ee", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "휴가 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Leave" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "휴가를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Leaves" + ], + "summary": "휴가 삭제", + "description": "대기 상태의 휴가만 삭제 가능합니다 (소프트 삭제).", + "operationId": "ec74135d6d235b8feb0342c492ad0401", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "휴가 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제 완료" + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "잘못된 요청 (삭제 불가 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "휴가를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Leaves" + ], + "summary": "휴가 수정", + "description": "대기 상태의 휴가만 수정 가능합니다.", + "operationId": "e25a32cefd45509e1725fad0e60de6a1", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "휴가 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LeaveUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Leave" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (수정 불가 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "휴가를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/leaves/{id}/approve": { + "post": { + "tags": [ + "Leaves" + ], + "summary": "휴가 승인", + "description": "대기 상태의 휴가를 승인합니다. 승인 시 잔여일수가 차감됩니다.", + "operationId": "cb136c83008acc5b3ee9b8953ff6da6d", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "휴가 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "comment": { + "description": "승인 코멘트", + "type": "string", + "example": "승인합니다." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "승인 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Leave" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (승인 불가 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "휴가를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/leaves/{id}/reject": { + "post": { + "tags": [ + "Leaves" + ], + "summary": "휴가 반려", + "description": "대기 상태의 휴가를 반려합니다.", + "operationId": "f05f46d0ed53181adfa4636b2d67c374", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "휴가 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "reason" + ], + "properties": { + "reason": { + "description": "반려 사유", + "type": "string", + "example": "인원 부족으로 반려합니다." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "반려 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Leave" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (반려 불가 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "휴가를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/leaves/{id}/cancel": { + "post": { + "tags": [ + "Leaves" + ], + "summary": "휴가 취소", + "description": "승인된 휴가를 취소합니다. 취소 시 잔여일수가 복구됩니다.", + "operationId": "7277e505faa941231796365b1e7bd813", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "휴가 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "reason": { + "description": "취소 사유", + "type": "string", + "example": "일정 변경으로 취소합니다." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "취소 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Leave" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (취소 불가 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "휴가를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/leaves/balance": { + "get": { + "tags": [ + "Leaves" + ], + "summary": "내 잔여 휴가 조회", + "description": "로그인한 사용자의 잔여 휴가를 조회합니다.", + "operationId": "7e643dd6ba425bd927cb99ee24352ccb", + "parameters": [ + { + "name": "year", + "in": "query", + "description": "연도 (미지정시 현재 연도)", + "schema": { + "type": "integer", + "example": 2024 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/LeaveBalance" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Leaves" + ], + "summary": "잔여 휴가 설정", + "description": "특정 사용자의 연간 휴가일수를 설정합니다 (관리자 전용).", + "operationId": "8437a0a4189681054d6fa943e4c6ef11", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LeaveBalanceSetRequest" + } + } + } + }, + "responses": { + "200": { + "description": "설정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/LeaveBalance" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/leaves/balance/{userId}": { + "get": { + "tags": [ + "Leaves" + ], + "summary": "특정 사용자 잔여 휴가 조회", + "description": "특정 사용자의 잔여 휴가를 조회합니다 (관리자 전용).", + "operationId": "896f788dfb060aff220cb1d6f55ab0f5", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "사용자 ID", + "required": true, + "schema": { + "type": "integer", + "example": 10 + } + }, + { + "name": "year", + "in": "query", + "description": "연도 (미지정시 현재 연도)", + "schema": { + "type": "integer", + "example": 2024 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/LeaveBalance" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "사용자를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/leave-policy": { + "get": { + "tags": [ + "LeavePolicy" + ], + "summary": "휴가 정책 조회", + "description": "현재 테넌트의 휴가 정책을 조회합니다. 설정이 없으면 기본값으로 생성됩니다.", + "operationId": "getLeavePolicy", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/LeavePolicy" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "LeavePolicy" + ], + "summary": "휴가 정책 수정", + "description": "현재 테넌트의 휴가 정책을 수정합니다. 부분 업데이트가 가능합니다.", + "operationId": "updateLeavePolicy", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LeavePolicyUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "정보가 수정되었습니다." + }, + "data": { + "$ref": "#/components/schemas/LeavePolicy" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + }, + "422": { + "description": "유효성 검사 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/loans": { + "get": { + "tags": [ + "Loans" + ], + "summary": "가지급금 목록 조회", + "description": "가지급금 목록을 조회합니다.", + "operationId": "cbfa44ba97d44669e107d8c302407ffe", + "parameters": [ + { + "name": "user_id", + "in": "query", + "description": "수령자 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "outstanding", + "settled", + "partial" + ] + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일 (지급일 기준)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일 (지급일 기준)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (수령자명, 목적)", + "schema": { + "type": "string", + "maxLength": 100 + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "loan_date", + "enum": [ + "loan_date", + "amount", + "status", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Loan" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 30 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Loans" + ], + "summary": "가지급금 등록", + "description": "새로운 가지급금을 등록합니다.", + "operationId": "8deada63321ba591e3b8e8617fe1b970", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoanCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Loan" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/loans/summary": { + "get": { + "tags": [ + "Loans" + ], + "summary": "가지급금 요약 조회", + "description": "가지급금 요약 정보를 조회합니다. 특정 사용자 지정 시 해당 사용자만 집계합니다.", + "operationId": "25e812ae70232d3467490593ca121499", + "parameters": [ + { + "name": "user_id", + "in": "query", + "description": "수령자 ID (미지정 시 전체)", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/LoanSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/loans/dashboard": { + "get": { + "tags": [ + "Loans" + ], + "summary": "가지급금 대시보드 조회", + "description": "CEO 대시보드 카드/가지급금 관리 섹션(cm2) 모달용 데이터를 조회합니다. 요약 정보와 최근 가지급금 목록을 반환합니다.", + "operationId": "f8032ad51e6b5220540d8dd5a65005a4", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/LoanDashboard" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/loans/tax-simulation": { + "get": { + "tags": [ + "Loans" + ], + "summary": "세금 시뮬레이션", + "description": "가지급금으로 인한 법인세/소득세 추가 부담을 시뮬레이션합니다. CEO 대시보드 카드/가지급금 관리 섹션(cm2)용.", + "operationId": "66330655e4ae320ceca086e2c306e9e0", + "parameters": [ + { + "name": "year", + "in": "query", + "description": "시뮬레이션 연도", + "required": true, + "schema": { + "type": "integer", + "maximum": 2100, + "minimum": 2000, + "example": 2026 + } + } + ], + "responses": { + "200": { + "description": "시뮬레이션 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/LoanTaxSimulation" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/loans/calculate-interest": { + "post": { + "tags": [ + "Loans" + ], + "summary": "인정이자 계산", + "description": "미정산 가지급금에 대한 인정이자를 계산합니다. 법인세/소득세/지방소득세가 자동 계산됩니다.", + "operationId": "1392c6a3905c1e1ceae187bdba299764", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "year" + ], + "properties": { + "year": { + "description": "계산 연도", + "type": "integer", + "maximum": 2100, + "minimum": 2000, + "example": 2025 + }, + "user_id": { + "description": "특정 사용자 ID (미지정 시 전체)", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "계산 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/LoanInterestCalculation" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/loans/interest-report/{year}": { + "get": { + "tags": [ + "Loans" + ], + "summary": "인정이자 연간 리포트", + "description": "특정 연도의 인정이자 리포트를 사용자별로 조회합니다.", + "operationId": "8279d8e6733b6fb9186af320bf74b610", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "연도", + "required": true, + "schema": { + "type": "integer", + "example": 2025 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/LoanInterestReport" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/loans/{id}": { + "get": { + "tags": [ + "Loans" + ], + "summary": "가지급금 상세 조회", + "description": "가지급금 상세 정보를 조회합니다.", + "operationId": "d23809a05dc79c8e833a1014f1e74288", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "가지급금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Loan" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "가지급금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Loans" + ], + "summary": "가지급금 수정", + "description": "가지급금 정보를 수정합니다. 미정산(outstanding) 상태에서만 수정 가능합니다.", + "operationId": "644818839c4d09fbdfd959e8e6679879", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "가지급금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoanUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Loan" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (정산됨/부분정산 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "가지급금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Loans" + ], + "summary": "가지급금 삭제", + "description": "가지급금을 삭제합니다. 미정산(outstanding) 상태에서만 삭제 가능합니다. (Soft Delete)", + "operationId": "092ae58e53a820c30682090e8e98ef8a", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "가지급금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "잘못된 요청 (정산됨/부분정산 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "가지급금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/loans/{id}/settle": { + "post": { + "tags": [ + "Loans" + ], + "summary": "가지급금 정산", + "description": "가지급금을 정산합니다. 미정산(outstanding) 또는 부분정산(partial) 상태에서만 가능합니다. 부분 정산 시 누적됩니다.", + "operationId": "08dfd3533041cc650ba23ba5b83f9b50", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "가지급금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoanSettleRequest" + } + } + } + }, + "responses": { + "200": { + "description": "정산 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Loan" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 (이미 정산 완료 또는 정산금액 초과)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "가지급금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/materials": { + "get": { + "tags": [ + "Material" + ], + "summary": "자재 목록 조회", + "description": "자재 목록을 페이징으로 반환합니다. (q로 코드/이름/태그 검색, category로 분류 필터)", + "operationId": "8951a0159ed65014c661af7650c6b54d", + "parameters": [ + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + }, + { + "name": "q", + "in": "query", + "description": "검색어(이름/코드/태그 등)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "category", + "in": "query", + "description": "카테고리 ID", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "자재 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 2 + }, + "data": { + "$ref": "#/components/schemas/MaterialList" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Material" + ], + "summary": "자재 등록", + "description": "자재를 등록합니다. item_name/specification은 name+attributes를 기반으로 서버에서 자동 생성됩니다.", + "operationId": "6a66daa0ef2c665d605b543ff5ae20bd", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MaterialCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "자재 등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Material" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/materials/{id}": { + "get": { + "tags": [ + "Material" + ], + "summary": "자재 단건 조회", + "operationId": "75bb9a6a09f6cdea28aedad027cec06b", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 101 + } + } + ], + "responses": { + "200": { + "description": "자재 단건 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Material" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Material" + ], + "summary": "자재 수정(전체)", + "description": "자재를 수정합니다. name/attributes 변경 시 item_name/specification이 서버에서 재계산됩니다.", + "operationId": "fa80df68a89a2672ebb469d3984fa2bd", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 101 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MaterialUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "자재 수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Material" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Material" + ], + "summary": "자재 삭제", + "description": "자재를 소프트 삭제합니다.", + "operationId": "8c8e2352da6becb305fa472814d033a2", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 101 + } + } + ], + "responses": { + "200": { + "description": "자재 삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Material" + ], + "summary": "자재 부분 수정", + "description": "자재의 일부 필드를 수정합니다. name/attributes 변경 시 item_name/specification이 서버에서 재계산됩니다.", + "operationId": "a650a94a6d2191583cd1b6d3dc0c00e0", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 101 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MaterialUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "자재 수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Material" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus": { + "get": { + "tags": [ + "Menu" + ], + "summary": "메뉴 목록 조회", + "description": "테넌트 범위 내(또는 공용) 메뉴 목록을 반환합니다. parent_id/is_active/hidden 필터 지원.", + "operationId": "fa63e168640744cc184888fe82051ac4", + "parameters": [ + { + "name": "parent_id", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 0 + } + }, + { + "name": "is_active", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "hidden", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 0 + } + } + ], + "responses": { + "200": { + "description": "목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/MenuList" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Menu" + ], + "summary": "메뉴 등록", + "description": "새로운 메뉴를 등록합니다.", + "operationId": "5fe416f19dda7cb6e15aa76bdc4d704a", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MenuCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "id": { + "type": "integer", + "example": 12 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "파라미터 오류", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/{id}": { + "get": { + "tags": [ + "Menu" + ], + "summary": "메뉴 단건 조회", + "description": "ID로 메뉴 상세 정보를 조회합니다.", + "operationId": "be7ff567d6145885ab351a1ac41e7e96", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "responses": { + "200": { + "description": "단건 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Menu" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Menu" + ], + "summary": "메뉴 삭제(소프트 삭제)", + "description": "지정한 메뉴를 소프트 삭제합니다.", + "operationId": "7c61cdda0ea3c8df41b3d2670c2d1d63", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "id": { + "type": "integer", + "example": 12 + }, + "deleted": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Menu" + ], + "summary": "메뉴 수정", + "description": "기존 메뉴 정보를 수정합니다(부분 수정).", + "operationId": "f2cbb557b50bb7a48a079f1d0b7c1410", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MenuUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "id": { + "type": "integer", + "example": 12 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "파라미터 오류", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/reorder": { + "post": { + "tags": [ + "Menu" + ], + "summary": "메뉴 정렬 변경", + "description": "여러 메뉴의 sort_order를 일괄 변경합니다.", + "operationId": "2d9a1d92a4f3ac0cf7935ec6f2b9468c", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 12 + }, + "sort_order": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + } + } + } + }, + "responses": { + "200": { + "description": "정렬 변경 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "파라미터 오류", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/{id}/toggle": { + "post": { + "tags": [ + "Menu" + ], + "summary": "메뉴 상태 토글", + "description": "is_active / hidden / is_external 중 하나 이상을 토글합니다.", + "operationId": "6a5ceb946801b2f41ea34b27962f1430", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "is_active": { + "type": "boolean", + "example": true, + "nullable": true + }, + "hidden": { + "type": "boolean", + "example": false, + "nullable": true + }, + "is_external": { + "type": "boolean", + "example": false, + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "토글 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "파라미터 오류", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/trashed": { + "get": { + "tags": [ + "Menu" + ], + "summary": "삭제된 메뉴 목록 조회", + "description": "소프트 삭제된 메뉴 목록을 조회합니다.", + "operationId": "e4973f2b0d8d7c326b9ca56598d12e62", + "responses": { + "200": { + "description": "삭제된 메뉴 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제된 메뉴 목록 조회" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Menu" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/{id}/restore": { + "post": { + "tags": [ + "Menu" + ], + "summary": "삭제된 메뉴 복원", + "description": "소프트 삭제된 메뉴를 복원합니다.", + "operationId": "897cb94001b8db6b476221fe39fb0753", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "복원할 메뉴 ID", + "required": true, + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "responses": { + "200": { + "description": "메뉴 복원 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "메뉴 복원" + }, + "data": { + "$ref": "#/components/schemas/Menu" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "메뉴 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/available-global": { + "get": { + "tags": [ + "Menu" + ], + "summary": "복제 가능한 글로벌 메뉴 목록", + "description": "테넌트에서 복제(동기화)할 수 있는 글로벌 메뉴 목록을 조회합니다.", + "operationId": "70f5c2633dbe40e36f0a81c08cec59f1", + "responses": { + "200": { + "description": "글로벌 메뉴 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "복제 가능한 글로벌 메뉴 목록" + }, + "data": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "대시보드" + }, + "url": { + "type": "string", + "example": "/dashboard", + "nullable": true + }, + "icon": { + "type": "string", + "example": "dashboard", + "nullable": true + }, + "is_synced": { + "description": "이미 동기화된 메뉴 여부", + "type": "boolean", + "example": false + }, + "has_updates": { + "description": "업데이트 필요 여부", + "type": "boolean", + "example": false + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/sync-status": { + "get": { + "tags": [ + "Menu" + ], + "summary": "동기화 상태 조회", + "description": "테넌트 메뉴와 글로벌 메뉴 간 동기화 상태를 조회합니다.", + "operationId": "698ca9062c6d70b26706fbe58c788bed", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "상태 필터 (new|synced|modified|outdated)", + "schema": { + "type": "string", + "example": "outdated" + } + } + ], + "responses": { + "200": { + "description": "동기화 상태 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "동기화 상태 조회" + }, + "data": { + "properties": { + "summary": { + "properties": { + "total": { + "type": "integer", + "example": 25 + }, + "synced": { + "type": "integer", + "example": 20 + }, + "new": { + "type": "integer", + "example": 3 + }, + "outdated": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + }, + "items": { + "type": "array", + "items": { + "properties": { + "global_menu_id": { + "type": "integer", + "example": 1 + }, + "tenant_menu_id": { + "type": "integer", + "example": 5, + "nullable": true + }, + "name": { + "type": "string", + "example": "대시보드" + }, + "status": { + "description": "new|synced|modified|outdated", + "type": "string", + "example": "synced" + }, + "last_synced_at": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/sync": { + "post": { + "tags": [ + "Menu" + ], + "summary": "메뉴 선택 동기화", + "description": "선택한 글로벌 메뉴를 테넌트에 동기화합니다. 신규 생성 또는 기존 메뉴 업데이트.", + "operationId": "008cc09c1f89fa17490f0abe5cf26fdd", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "menu_ids": { + "description": "동기화할 글로벌 메뉴 ID 목록", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + }, + "force": { + "description": "강제 덮어쓰기 여부 (커스텀 변경사항 무시)", + "type": "boolean", + "example": false + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "동기화 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "메뉴 동기화" + }, + "data": { + "properties": { + "created": { + "type": "integer", + "example": 2 + }, + "updated": { + "type": "integer", + "example": 1 + }, + "skipped": { + "type": "integer", + "example": 0 + }, + "details": { + "type": "array", + "items": { + "properties": { + "menu_id": { + "type": "integer" + }, + "action": { + "type": "string", + "example": "created" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "파라미터 오류", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/sync-new": { + "post": { + "tags": [ + "Menu" + ], + "summary": "신규 글로벌 메뉴 일괄 가져오기", + "description": "아직 동기화되지 않은 신규 글로벌 메뉴를 일괄 가져옵니다.", + "operationId": "37cc33bb4ca372f95826a5abdc928c71", + "responses": { + "200": { + "description": "신규 메뉴 가져오기 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "신규 메뉴 가져오기" + }, + "data": { + "properties": { + "imported": { + "type": "integer", + "example": 5 + }, + "menus": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MenuBrief" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/menus/sync-updates": { + "post": { + "tags": [ + "Menu" + ], + "summary": "변경된 메뉴 일괄 업데이트", + "description": "글로벌 메뉴에서 변경된 내용을 테넌트 메뉴에 일괄 반영합니다. 커스텀 수정된 메뉴는 제외됩니다.", + "operationId": "ee6691e151bd39cc9675939354f148b5", + "responses": { + "200": { + "description": "업데이트 동기화 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "메뉴 업데이트 동기화" + }, + "data": { + "properties": { + "updated": { + "type": "integer", + "example": 3 + }, + "skipped": { + "description": "커스텀 수정으로 스킵된 메뉴 수", + "type": "integer", + "example": 2 + }, + "details": { + "type": "array", + "items": { + "properties": { + "menu_id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "action": { + "type": "string", + "example": "updated|skipped" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/model-sets": { + "get": { + "tags": [ + "ModelSet" + ], + "summary": "모델셋 목록 조회", + "description": "견적 카테고리 기반 모델셋 목록을 조회합니다.", + "operationId": "51d989c95fe3f57d1a4d88c81eddb328", + "parameters": [ + { + "name": "category_type", + "in": "query", + "description": "카테고리 유형", + "schema": { + "type": "string", + "example": "screen_product" + } + }, + { + "name": "is_active", + "in": "query", + "description": "활성화 여부", + "schema": { + "type": "boolean", + "example": true + } + } + ], + "responses": { + "200": { + "description": "모델셋 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터 조회" + }, + "data": { + "properties": { + "model_sets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelSet" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "ModelSet" + ], + "summary": "모델셋 생성", + "description": "새로운 모델셋(견적 카테고리)을 생성합니다. 옵션으로 기본 모델 및 BOM 템플릿도 함께 생성할 수 있습니다.", + "operationId": "bfc0463404597c168922422639add9e8", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelSetCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "모델셋 생성 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터 생성" + }, + "data": { + "properties": { + "model_set": { + "$ref": "#/components/schemas/ModelSetDetail" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/model-sets/{id}": { + "get": { + "tags": [ + "ModelSet" + ], + "summary": "모델셋 상세 조회", + "description": "모델셋의 상세 정보(카테고리, 제품, 모델, 필드 스키마)를 조회합니다.", + "operationId": "403102bf73b5b9a2061f7449ff58f5fd", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "모델셋(카테고리) ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "모델셋 상세 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터 조회" + }, + "data": { + "properties": { + "model_set": { + "$ref": "#/components/schemas/ModelSetDetail" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "모델셋 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "ModelSet" + ], + "summary": "모델셋 수정", + "description": "모델셋 정보를 수정합니다. 필드 배열이 전달되면 기존 필드를 삭제하고 새로 생성합니다.", + "operationId": "3f2516c7f9336e3eaac1317aebd71255", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "모델셋(카테고리) ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelSetUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "모델셋 수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터 수정" + }, + "data": { + "properties": { + "model_set": { + "$ref": "#/components/schemas/ModelSetDetail" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "모델셋 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "ModelSet" + ], + "summary": "모델셋 삭제", + "description": "모델셋을 삭제합니다. 연관된 제품이나 하위 카테고리가 있으면 삭제할 수 없습니다.", + "operationId": "8899030a0ecc7a70d51d1153ccb78908", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "모델셋(카테고리) ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "모델셋 삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터 삭제" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "모델셋 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "400": { + "description": "삭제 불가 (연관 데이터 존재)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/model-sets/{id}/clone": { + "post": { + "tags": [ + "ModelSet" + ], + "summary": "모델셋 복제", + "description": "기존 모델셋을 복제하여 새로운 모델셋을 생성합니다. 필드 정의도 함께 복제됩니다.", + "operationId": "a8ce1b2bf208603d34108d1cc08e9a82", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "복제할 모델셋(카테고리) ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelSetCloneRequest" + } + } + } + }, + "responses": { + "200": { + "description": "모델셋 복제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "모델셋 복제 완료" + }, + "data": { + "properties": { + "model_set": { + "$ref": "#/components/schemas/ModelSetDetail" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "원본 모델셋 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/model-sets/{id}/fields": { + "get": { + "tags": [ + "ModelSet" + ], + "summary": "모델셋 필드 구조 조회", + "description": "모델셋의 카테고리별 필드 구조(스키마)를 조회합니다.", + "operationId": "93de659598dbc01457cbf0a2b400cf3b", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "모델셋(카테고리) ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "필드 구조 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터 조회" + }, + "data": { + "properties": { + "category_fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelSetField" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "모델셋 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/model-sets/{id}/bom-templates": { + "get": { + "tags": [ + "ModelSet" + ], + "summary": "모델셋 BOM 템플릿 목록", + "description": "모델셋과 연관된 모델들의 BOM 템플릿 목록을 조회합니다.", + "operationId": "dfce02a9dfa3ba8888fe1b86f6acdc4a", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "모델셋(카테고리) ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "BOM 템플릿 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터 조회" + }, + "data": { + "properties": { + "bom_templates": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "model_version_id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "스크린 기본 BOM" + }, + "company_type": { + "type": "string", + "example": "경동기업" + }, + "formula_version": { + "type": "string", + "example": "v1.0" + }, + "calculation_schema": { + "type": "object" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "모델셋 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/model-sets/{id}/estimate-parameters": { + "get": { + "tags": [ + "ModelSet" + ], + "summary": "견적 파라미터 조회", + "description": "모델셋의 견적 계산에 필요한 입력 파라미터와 계산 결과 필드를 조회합니다.", + "operationId": "bd46a370ad9cb358e323949d7e1baf7e", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "모델셋(카테고리) ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "견적 파라미터 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터 조회" + }, + "data": { + "properties": { + "parameters": { + "$ref": "#/components/schemas/ModelSetEstimateParameters" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "모델셋 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/model-sets/{id}/calculate-bom": { + "post": { + "tags": [ + "ModelSet" + ], + "summary": "BOM 계산", + "description": "입력 파라미터를 기반으로 BOM을 계산합니다. 크기 계산, 자재 수량 산출, 비용 계산이 수행됩니다.", + "operationId": "ad013ec8c240008e43b01f3b0fe7d55d", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "모델셋(카테고리) ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelSetBomCalculationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "BOM 계산 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "계산 완료" + }, + "data": { + "$ref": "#/components/schemas/ModelSetBomCalculationResult" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "모델셋 또는 BOM 템플릿 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/me/notification-settings": { + "get": { + "tags": [ + "NotificationSetting" + ], + "summary": "알림 설정 조회", + "description": "현재 사용자의 알림 설정을 조회합니다.", + "operationId": "getNotificationSettings", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "$ref": "#/components/schemas/NotificationSettingResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "NotificationSetting" + ], + "summary": "알림 설정 업데이트", + "description": "특정 알림 유형의 설정을 업데이트합니다.", + "operationId": "updateNotificationSetting", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateNotificationSettingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "수정 성공" + }, + "data": { + "$ref": "#/components/schemas/NotificationSettingItem" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/me/notification-settings/bulk": { + "put": { + "tags": [ + "NotificationSetting" + ], + "summary": "알림 설정 일괄 업데이트", + "description": "여러 알림 유형의 설정을 일괄 업데이트합니다.", + "operationId": "bulkUpdateNotificationSettings", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkUpdateNotificationSettingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 저장 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "대량 저장 성공" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationSettingItem" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/notifications": { + "get": { + "tags": [ + "NotificationSetting" + ], + "summary": "그룹 기반 알림 설정 조회 (React 호환)", + "description": "React 프론트엔드 구조에 맞춘 그룹 기반 알림 설정을 조회합니다.", + "operationId": "getGroupedNotificationSettings", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "$ref": "#/components/schemas/NotificationSettingGrouped" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "NotificationSetting" + ], + "summary": "그룹 기반 알림 설정 업데이트 (React 호환)", + "description": "React 프론트엔드 구조에 맞춘 그룹 기반 알림 설정을 업데이트합니다.", + "operationId": "updateGroupedNotificationSettings", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationSettingGrouped" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "수정 성공" + }, + "data": { + "$ref": "#/components/schemas/NotificationSettingGrouped" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/orders": { + "get": { + "tags": [ + "Order" + ], + "summary": "수주 목록 조회", + "description": "수주 목록을 페이징하여 조회합니다.", + "operationId": "45c7b83e9b1cfa7c431cd41a9eb55d97", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "검색어 (수주번호, 현장명, 거래처명)", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "DRAFT", + "CONFIRMED", + "IN_PROGRESS", + "COMPLETED", + "CANCELLED" + ] + } + }, + { + "name": "order_type", + "in": "query", + "description": "주문유형 필터", + "schema": { + "type": "string", + "enum": [ + "ORDER", + "PURCHASE" + ] + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "date_from", + "in": "query", + "description": "수주일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "date_to", + "in": "query", + "description": "수주일 종료", + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/OrderPagination" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Order" + ], + "summary": "수주 생성", + "description": "새로운 수주를 생성합니다.", + "operationId": "040982d7511a374810c221f3447d7c42", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Order" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/orders/stats": { + "get": { + "tags": [ + "Order" + ], + "summary": "수주 통계 조회", + "description": "상태별 수주 건수와 금액을 조회합니다.", + "operationId": "959890cc605c0f5bdbff9afa4a6a977e", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/OrderStats" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/orders/{id}": { + "get": { + "tags": [ + "Order" + ], + "summary": "수주 상세 조회", + "description": "특정 수주의 상세 정보를 조회합니다.", + "operationId": "1fddf6b520e8861661b472c3805ca625", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Order" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "수주를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Order" + ], + "summary": "수주 수정", + "description": "기존 수주를 수정합니다. 완료/취소 상태에서는 수정할 수 없습니다.", + "operationId": "2a2f13aecb2aedaaefb75cded34b7873", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Order" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "수정 불가 상태" + }, + "404": { + "description": "수주를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Order" + ], + "summary": "수주 삭제", + "description": "수주를 삭제합니다. 진행 중이거나 완료된 수주는 삭제할 수 없습니다.", + "operationId": "f6cbc2d2af06b275d2b79192c841813d", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "삭제 불가 상태" + }, + "404": { + "description": "수주를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/orders/{id}/status": { + "patch": { + "tags": [ + "Order" + ], + "summary": "수주 상태 변경", + "description": "수주의 상태를 변경합니다. 상태 전환 규칙에 따라 유효한 상태로만 변경 가능합니다.", + "operationId": "e2171f4e397ff57e9bdabe5afd2393ff", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderStatusRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Order" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "유효하지 않은 상태 전환" + }, + "404": { + "description": "수주를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payments": { + "get": { + "tags": [ + "Payments" + ], + "summary": "결제 목록 조회", + "description": "테넌트의 결제 목록을 조회합니다.", + "operationId": "0a42200e5a89b340c94ae0908f30bd9c", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "pending", + "completed", + "failed", + "cancelled", + "refunded" + ] + } + }, + { + "name": "payment_method", + "in": "query", + "description": "결제 수단", + "schema": { + "type": "string", + "enum": [ + "card", + "bank", + "virtual", + "cash", + "free" + ] + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일 (결제일 기준)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일 (결제일 기준)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (거래ID, 메모)", + "schema": { + "type": "string", + "maxLength": 100 + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "created_at", + "paid_at", + "amount" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Payment" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Payments" + ], + "summary": "결제 등록 (수동)", + "description": "수동으로 결제를 등록합니다.", + "operationId": "6358dff5d0f97ec1a78de1b5816c2f0b", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payment" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "구독 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payments/summary": { + "get": { + "tags": [ + "Payments" + ], + "summary": "결제 요약 통계", + "description": "테넌트의 결제 요약 통계를 조회합니다.", + "operationId": "ddb18978ae22b6a641419a49bfc2b2ef", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PaymentSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payments/{id}": { + "get": { + "tags": [ + "Payments" + ], + "summary": "결제 상세 조회", + "description": "결제 상세 정보를 조회합니다.", + "operationId": "11b6e6f51b6d747cba192fe108ef73fd", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "결제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payment" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "결제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payments/{id}/complete": { + "post": { + "tags": [ + "Payments" + ], + "summary": "결제 완료 처리", + "description": "대기 중인 결제를 완료 처리합니다.", + "operationId": "317e07ed0168f038d7f935f2af90ad9d", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "결제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "transaction_id": { + "description": "PG 거래 ID", + "type": "string", + "example": "TXN123456789" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "완료 처리 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payment" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "완료 처리 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "결제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payments/{id}/cancel": { + "post": { + "tags": [ + "Payments" + ], + "summary": "결제 취소", + "description": "결제를 취소합니다. 대기(pending) 또는 완료(completed) 상태에서만 가능합니다.", + "operationId": "744692133b80f5b37d214fc63693775f", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "결제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentActionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "취소 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payment" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "취소 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "결제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payments/{id}/refund": { + "post": { + "tags": [ + "Payments" + ], + "summary": "환불 처리", + "description": "완료된 결제를 환불 처리합니다. 완료(completed) 상태에서만 가능합니다.", + "operationId": "75e7d297edaeb78b92ff629d5ff32da9", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "결제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentActionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "환불 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payment" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "환불 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "결제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payments/{id}/statement": { + "get": { + "tags": [ + "Payments" + ], + "summary": "결제 명세서 조회", + "description": "결제 명세서를 조회합니다. 구독, 요금제, 고객 정보를 포함한 상세 명세서를 반환합니다.", + "operationId": "ab578732f093164db3c4253359703ac5", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "결제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PaymentStatement" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "결제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payrolls": { + "get": { + "tags": [ + "Payrolls" + ], + "summary": "급여 목록 조회", + "description": "급여 목록을 페이지네이션하여 조회합니다.", + "operationId": "b0774b209b9faeb0d64ae70d1d6bbe31", + "parameters": [ + { + "name": "year", + "in": "query", + "description": "지급 연도", + "schema": { + "type": "integer", + "example": 2024 + } + }, + { + "name": "month", + "in": "query", + "description": "지급 월", + "schema": { + "type": "integer", + "example": 12 + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "draft", + "confirmed", + "paid" + ] + } + }, + { + "name": "user_id", + "in": "query", + "description": "직원 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (직원명)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "pay_year", + "enum": [ + "pay_year", + "pay_month", + "base_salary", + "net_salary", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Payroll" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Payrolls" + ], + "summary": "급여 생성", + "operationId": "7b4a389f0b7c552b6352b6c253e11fdb", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PayrollStoreRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payroll" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "해당 연월 급여 이미 존재", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payrolls/summary": { + "get": { + "tags": [ + "Payrolls" + ], + "summary": "급여 현황 요약", + "description": "급여 상태별 건수와 금액을 조회합니다.", + "operationId": "925f03cf320900f6b6a5872a193ff0fc", + "parameters": [ + { + "name": "year", + "in": "query", + "description": "지급 연도", + "schema": { + "type": "integer", + "example": 2024 + } + }, + { + "name": "month", + "in": "query", + "description": "지급 월", + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PayrollSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payrolls/{id}": { + "get": { + "tags": [ + "Payrolls" + ], + "summary": "급여 상세 조회", + "operationId": "90139c7d7b1f3f27d1a01605e9b01915", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "급여 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payroll" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "급여를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Payrolls" + ], + "summary": "급여 수정", + "description": "작성중 상태의 급여만 수정할 수 있습니다.", + "operationId": "beea8c9ef3345f91d2c30b3baed7fdb6", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "급여 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PayrollUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payroll" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "수정 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "급여를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Payrolls" + ], + "summary": "급여 삭제", + "description": "작성중 상태의 급여만 삭제할 수 있습니다.", + "operationId": "471c5752e9ea7c74020dbc0f9b4d2b20", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "급여 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제 완료" + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "삭제 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "급여를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payrolls/{id}/confirm": { + "post": { + "tags": [ + "Payrolls" + ], + "summary": "급여 확정", + "description": "작성중 상태의 급여를 확정합니다.", + "operationId": "aa4014a18945188fb0c9631f180bd0da", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "급여 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "확정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payroll" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "확정 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "급여를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payrolls/{id}/pay": { + "post": { + "tags": [ + "Payrolls" + ], + "summary": "급여 지급 처리", + "description": "확정된 급여를 지급 처리합니다. 출금 내역과 연결할 수 있습니다.", + "operationId": "2a16739e004ba7060fde942c6d750234", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "급여 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "withdrawal_id": { + "description": "출금 내역 ID (선택)", + "type": "integer", + "example": 123 + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "지급 처리 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payroll" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "지급 불가 상태 또는 출금 내역 오류", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "급여를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payrolls/bulk-confirm": { + "post": { + "tags": [ + "Payrolls" + ], + "summary": "급여 일괄 확정", + "description": "지정 기간의 작성중 급여를 일괄 확정합니다.", + "operationId": "29c936e844fbc2cdc7536f06c8a7a0d1", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "year", + "month" + ], + "properties": { + "year": { + "description": "지급 연도", + "type": "integer", + "example": 2024 + }, + "month": { + "description": "지급 월", + "type": "integer", + "example": 12 + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 확정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "confirmed_count": { + "description": "확정된 건수", + "type": "integer", + "example": 45 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payrolls/calculate": { + "post": { + "tags": [ + "Payrolls" + ], + "summary": "급여 일괄 계산", + "description": "지정 기간의 급여를 일괄 계산하여 생성합니다. 이미 존재하는 급여는 건너뜁니다.", + "operationId": "19078d08577fc1a7994f4ecaaa95687f", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PayrollCalculateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 계산 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "created_count": { + "description": "생성된 건수", + "type": "integer", + "example": 45 + }, + "skipped_count": { + "description": "건너뛴 건수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/payrolls/{id}/payslip": { + "get": { + "tags": [ + "Payrolls" + ], + "summary": "급여명세서 조회", + "description": "급여명세서 형식으로 급여 정보를 조회합니다.", + "operationId": "5a1bac1eaac0ecaeaa965bedc4431409", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "급여 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Payslip" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "급여를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/payroll": { + "get": { + "tags": [ + "Payrolls" + ], + "summary": "급여 설정 조회", + "description": "테넌트의 급여 설정을 조회합니다.", + "operationId": "173a2a2a69d7986428f13c48ba83d658", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PayrollSetting" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Payrolls" + ], + "summary": "급여 설정 수정", + "description": "테넌트의 급여 설정을 수정합니다.", + "operationId": "7c9246a9c0d0de792df5529ceaf41573", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PayrollSettingUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PayrollSetting" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/permissions/departments/{dept_id}/menu-matrix": { + "get": { + "tags": [ + "Permission" + ], + "summary": "부서 메뉴 권한 매트릭스", + "description": "부서 기준으로 메뉴 트리 및 액션별 권한 상태(allow/deny/none)를 반환합니다.", + "operationId": "7862c55c36677ef893ae4d8b3cc740ec", + "parameters": [ + { + "name": "dept_id", + "in": "path", + "description": "부서 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "부서 메뉴 권한 매트릭스 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/MenuMatrixPayload" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "부서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/permissions/roles/{role_id}/menu-matrix": { + "get": { + "tags": [ + "Permission" + ], + "summary": "역할 메뉴 권한 매트릭스", + "description": "스파티 기본 Role 기준으로 메뉴 트리 및 액션별 권한 상태(allow/deny/none)를 반환합니다.", + "operationId": "2dd44e69a3a8b52e599b2fa454479676", + "parameters": [ + { + "name": "role_id", + "in": "path", + "description": "역할 ID", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "responses": { + "200": { + "description": "역할 메뉴 권한 매트릭스 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/MenuMatrixPayload" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "역할 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/permissions/users/{user_id}/menu-matrix": { + "get": { + "tags": [ + "Permission" + ], + "summary": "사용자 메뉴 권한 매트릭스", + "description": "사용자 기준으로 메뉴 트리 및 액션별 권한 상태(allow/deny/none)를 반환합니다.", + "operationId": "d1d17c827d944ed579fb4bd0dc02224e", + "parameters": [ + { + "name": "user_id", + "in": "path", + "description": "사용자 ID", + "required": true, + "schema": { + "type": "integer", + "example": 12 + } + } + ], + "responses": { + "200": { + "description": "유저 메뉴 권한 매트릭스 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/MenuMatrixPayload" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "사용자 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/plans": { + "get": { + "tags": [ + "Plans" + ], + "summary": "요금제 목록 조회", + "description": "요금제 목록을 조회합니다. (관리자용)", + "operationId": "a6673651c50239428cef327b9aaccc40", + "parameters": [ + { + "name": "is_active", + "in": "query", + "description": "활성 상태 필터", + "schema": { + "type": "boolean" + } + }, + { + "name": "billing_cycle", + "in": "query", + "description": "결제 주기", + "schema": { + "type": "string", + "enum": [ + "monthly", + "yearly", + "lifetime" + ] + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (이름, 코드, 설명)", + "schema": { + "type": "string", + "maxLength": 100 + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "price", + "enum": [ + "price", + "name", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "asc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Plan" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Plans" + ], + "summary": "요금제 등록", + "description": "새로운 요금제를 등록합니다.", + "operationId": "1f0dbb39f38b0b73b36dea90a07f1979", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Plan" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/plans/active": { + "get": { + "tags": [ + "Plans" + ], + "summary": "활성 요금제 목록", + "description": "활성화된 요금제 목록을 조회합니다. (공개용)", + "operationId": "66edeba75d06d40dba499bbd2d7f85b9", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Plan" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/plans/{id}": { + "get": { + "tags": [ + "Plans" + ], + "summary": "요금제 상세 조회", + "description": "요금제 상세 정보를 조회합니다.", + "operationId": "15a332ad49fcd0901383dcfcee3be044", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "요금제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Plan" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "요금제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Plans" + ], + "summary": "요금제 수정", + "description": "요금제 정보를 수정합니다.", + "operationId": "a24bc7239894e0e90a7c83bda6b63502", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "요금제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Plan" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "요금제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Plans" + ], + "summary": "요금제 삭제", + "description": "요금제를 삭제합니다. 활성 구독이 있으면 삭제할 수 없습니다. (Soft Delete)", + "operationId": "437da4b6436ab8dec560556aa07084f3", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "요금제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "활성 구독 존재", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "요금제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/plans/{id}/toggle": { + "patch": { + "tags": [ + "Plans" + ], + "summary": "요금제 활성/비활성 토글", + "description": "요금제의 활성 상태를 토글합니다.", + "operationId": "2d4f4fbde5f2cc076d7ff842c4b0a340", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "요금제 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "토글 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Plan" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "요금제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/popups": { + "get": { + "tags": [ + "Popup" + ], + "summary": "팝업 목록 조회 (관리자용)", + "operationId": "83aa41606ec5ec3f857805bd18e6f4b2", + "parameters": [ + { + "name": "target_type", + "in": "query", + "description": "대상 유형", + "schema": { + "type": "string", + "enum": [ + "all", + "department" + ] + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + } + }, + { + "name": "search", + "in": "query", + "description": "검색어 (제목, 내용)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at" + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PopupPagination" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Popup" + ], + "summary": "팝업 등록", + "operationId": "cf40833f3ee360ef0d72ad7c6f98ee55", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PopupCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Popup" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/popups/active": { + "get": { + "tags": [ + "Popup" + ], + "summary": "활성 팝업 목록 조회 (사용자용 - 로그인 후 노출)", + "description": "현재 노출 중인 팝업 목록을 반환합니다. status=active이고 현재 시간이 started_at~ended_at 범위에 있는 팝업만 조회됩니다.", + "operationId": "ad9de285380e41b4717205ded804f750", + "parameters": [ + { + "name": "department_id", + "in": "query", + "description": "사용자의 부서 ID (해당 부서 대상 팝업 포함)", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Popup" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/popups/{id}": { + "get": { + "tags": [ + "Popup" + ], + "summary": "팝업 상세 조회", + "operationId": "776dbc1275b6613597d7a47b91abe55b", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Popup" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Popup" + ], + "summary": "팝업 수정", + "operationId": "83bb4347a81bc6a9823ee44ac3b42fd8", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PopupUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Popup" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Popup" + ], + "summary": "팝업 삭제", + "operationId": "b040552f47edecbb9a87654d046f4300", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "null" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/positions": { + "get": { + "tags": [ + "Position" + ], + "summary": "직급/직책 목록 조회", + "operationId": "14f490c5bc4597ec1b307add1b6b0d71", + "parameters": [ + { + "name": "type", + "in": "query", + "description": "유형 필터 (rank: 직급, title: 직책)", + "schema": { + "type": "string", + "enum": [ + "rank", + "title" + ] + } + }, + { + "name": "is_active", + "in": "query", + "description": "활성화 필터", + "schema": { + "type": "boolean" + } + }, + { + "name": "q", + "in": "query", + "description": "검색어 (명칭)", + "schema": { + "type": "string" + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 개수 (생략시 전체)", + "schema": { + "type": "integer" + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Position" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Position" + ], + "summary": "직급/직책 생성", + "operationId": "b4cf38bda5c04608b79c67468d92890f", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PositionCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Position" + } + }, + "type": "object" + } + } + } + }, + "409": { + "description": "중복 오류" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/positions/{id}": { + "get": { + "tags": [ + "Position" + ], + "summary": "직급/직책 단건 조회", + "operationId": "a1de1e293b40e65d4fc330a54bf45868", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Position" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Position" + ], + "summary": "직급/직책 수정", + "operationId": "366e1636c176f8b07dfa21f0bcfb5f32", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PositionUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Position" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "찾을 수 없음" + }, + "409": { + "description": "중복 오류" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Position" + ], + "summary": "직급/직책 삭제", + "operationId": "342f2a94d1742bc7285105876dbdfebf", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "id": { + "type": "integer" + }, + "deleted_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/positions/reorder": { + "put": { + "tags": [ + "Position" + ], + "summary": "직급/직책 순서 변경 (벌크)", + "operationId": "06ba4f58e43a75f234b9e139d35d80dd", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PositionReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "success": { + "type": "boolean" + }, + "updated": { + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/posts/my": { + "get": { + "tags": [ + "Post" + ], + "summary": "나의 게시글 목록", + "description": "로그인한 사용자가 작성한 모든 게시글을 조회합니다.", + "operationId": "251b59c26b9846e1f4f97534c0fe2df3", + "parameters": [ + { + "name": "board_code", + "in": "query", + "description": "게시판 코드 필터", + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "제목/내용 검색", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "draft", + "published", + "hidden" + ] + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "per_page", + "in": "query", + "schema": { + "type": "integer", + "example": 15 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PostPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards/{code}/posts": { + "get": { + "tags": [ + "Post" + ], + "summary": "게시글 목록", + "operationId": "c6cc5b85c66d15de29bb94970197ad1a", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "per_page", + "in": "query", + "schema": { + "type": "integer", + "example": 15 + } + }, + { + "name": "search", + "in": "query", + "description": "제목/내용 검색", + "schema": { + "type": "string" + } + }, + { + "name": "is_notice", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "draft", + "published", + "hidden" + ] + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PostPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Post" + ], + "summary": "게시글 작성", + "operationId": "e0d50ec87841f405089d96dcb2c3c6cd", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "작성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Post" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards/{code}/posts/{id}": { + "get": { + "tags": [ + "Post" + ], + "summary": "게시글 상세 (조회수 자동 증가)", + "operationId": "4292ff85d107a9c3e322513fa3f32334", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Post" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Post" + ], + "summary": "게시글 수정", + "operationId": "eb6f20b211ca34a75a19465717fb873a", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Post" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Post" + ], + "summary": "게시글 삭제", + "operationId": "f12617c508511d0dbeb394de8470f601", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "게시글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards/{code}/posts/{postId}/comments": { + "get": { + "tags": [ + "Post" + ], + "summary": "댓글 목록", + "operationId": "dda488a994ba04de43f559b3c8a78a78", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Comment" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Post" + ], + "summary": "댓글 작성", + "operationId": "bdc380836cc3bd8c93e80f6d79629cb3", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "작성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Comment" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/boards/{code}/posts/{postId}/comments/{commentId}": { + "put": { + "tags": [ + "Post" + ], + "summary": "댓글 수정", + "description": "본인이 작성한 댓글만 수정 가능", + "operationId": "d5e48e8baa1c9c802876b302fc657e5a", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "commentId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Comment" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "댓글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Post" + ], + "summary": "댓글 삭제", + "description": "본인이 작성한 댓글만 삭제 가능 (상태가 deleted로 변경됨)", + "operationId": "dfa905aa32155bae3d34500791683add", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "commentId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "댓글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/pricing": { + "get": { + "tags": [ + "Pricing" + ], + "summary": "단가 목록 조회", + "operationId": "d0c45f022ce680907a0e5194c36a9c8e", + "parameters": [ + { + "name": "q", + "in": "query", + "description": "검색어 (supplier, note)", + "schema": { + "type": "string" + } + }, + { + "name": "item_type_code", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ] + } + }, + { + "name": "item_id", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "client_group_id", + "in": "query", + "description": "고객그룹 ID (빈값/null=기본가만)", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "draft", + "active", + "inactive", + "finalized" + ] + } + }, + { + "name": "valid_at", + "in": "query", + "description": "특정 날짜에 유효한 단가만", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "example": 20 + } + }, + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PricePagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Pricing" + ], + "summary": "단가 등록", + "operationId": "a7142814e8ac6a5ebb0417187a3da5fa", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Price" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/pricing/{id}": { + "get": { + "tags": [ + "Pricing" + ], + "summary": "단가 상세 조회", + "operationId": "3a0cd5212bf5b1741d3e83eb279fb6af", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Price" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "미존재", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Pricing" + ], + "summary": "단가 수정", + "description": "확정(finalized) 상태의 단가는 수정 불가", + "operationId": "0a47b824316ab662a9aa338d5d2cc672", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Price" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "수정 불가 (확정된 단가)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Pricing" + ], + "summary": "단가 삭제 (soft)", + "description": "확정(finalized) 상태의 단가는 삭제 불가", + "operationId": "fd9e703b7f871268d17151f70f3e7be7", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "삭제 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/pricing/{id}/finalize": { + "post": { + "tags": [ + "Pricing" + ], + "summary": "단가 확정", + "description": "단가를 확정 상태로 변경 (확정 후 수정/삭제 불가)", + "operationId": "886e5004c124aade48047fbdda33b88e", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "확정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Price" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "확정 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/pricing/by-items": { + "post": { + "tags": [ + "Pricing" + ], + "summary": "품목별 단가 현황 조회", + "description": "여러 품목의 현재 유효한 단가를 한번에 조회", + "operationId": "541dfcb106b5f58dc82c137a1003d1b2", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceByItemsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PriceByItemsResult" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/pricing/{id}/revisions": { + "get": { + "tags": [ + "Pricing" + ], + "summary": "변경 이력 조회", + "operationId": "b77a3681c94a58b580a48e6aef4a2d20", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "example": 20 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PriceRevision" + } + }, + "total": { + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "단가 미존재", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/pricing/cost": { + "get": { + "tags": [ + "Pricing" + ], + "summary": "원가 조회", + "description": "품목의 원가를 조회. 자재는 수입검사 입고단가 우선, 없으면 표준원가 사용", + "operationId": "71eb592eaaec7382e327672e1c19fe31", + "parameters": [ + { + "name": "item_type_code", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ] + } + }, + { + "name": "item_id", + "in": "query", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "date", + "in": "query", + "description": "기준일 (미지정시 오늘)", + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PriceCostResult" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/processes": { + "get": { + "tags": [ + "Process" + ], + "summary": "공정 목록 조회", + "operationId": "8353b62af2f6e17fe5d9c97ede29694f", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "검색어", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + } + }, + { + "name": "process_type", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "생산", + "검사", + "포장", + "조립" + ] + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Process" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Process" + ], + "summary": "공정 생성", + "operationId": "9cb0f2b004886876ee6288bd0612d4fd", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProcessCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성됨", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "message.created" + }, + "data": { + "$ref": "#/components/schemas/Process" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/processes/{id}": { + "get": { + "tags": [ + "Process" + ], + "summary": "공정 상세 조회", + "operationId": "15e181b10633c34934a5948be0f4d372", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "data": { + "$ref": "#/components/schemas/Process" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Process" + ], + "summary": "공정 수정", + "operationId": "817a8674559cfb9327c685c53b84d3d3", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProcessCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "message.updated" + }, + "data": { + "$ref": "#/components/schemas/Process" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/product/category": { + "get": { + "tags": [ + "Products" + ], + "summary": "제품 카테고리 목록 조회", + "description": "제품 카테고리(최상위: parent_id = null) 리스트를 반환합니다.", + "operationId": "a31d613437a2730fddd0d5adbcd14f77", + "responses": { + "200": { + "description": "카테고리 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProductCategory" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products": { + "get": { + "tags": [ + "Products" + ], + "summary": "제품 목록/검색", + "description": "제품 목록/검색", + "operationId": "0e450dd3dcb11e4eee6059ee28e642f1", + "parameters": [ + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + }, + { + "name": "q", + "in": "query", + "description": "코드/이름/설명 검색", + "schema": { + "type": "string" + } + }, + { + "name": "category_id", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "product_type", + "in": "query", + "schema": { + "type": "string", + "example": "PRODUCT" + } + }, + { + "name": "active", + "in": "query", + "schema": { + "type": "integer", + "enum": [ + 0, + 1 + ] + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ProductPagination" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Products" + ], + "summary": "제품 생성", + "description": "제품 생성", + "operationId": "e324c796693fe14aa8d4489cb6f60923", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Product" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}": { + "get": { + "tags": [ + "Products" + ], + "summary": "제품 단건 조회", + "description": "제품 단건", + "operationId": "5f1be6796061a58d0de00de5e83c6c2d", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Product" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Products" + ], + "summary": "제품 삭제(soft)", + "description": "제품 삭제(soft)", + "operationId": "a58c49f873d359de47796a6a65b4f57c", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Products" + ], + "summary": "제품 수정", + "description": "제품 수정", + "operationId": "5ff449bb322c621a7da357998014c9ed", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Product" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/search": { + "get": { + "tags": [ + "Products" + ], + "summary": "제품 간편 검색", + "description": "제품 간편 검색(모달/드롭다운)", + "operationId": "c249826a6d7bb69931dd4e6bfb0e4a9c", + "parameters": [ + { + "name": "q", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "기본 20", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "검색 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 101 + }, + "code": { + "type": "string", + "example": "PRD-001" + }, + "name": { + "type": "string", + "example": "스크린 모듈 KS001" + }, + "product_type": { + "type": "string", + "example": "PRODUCT" + }, + "category_id": { + "type": "integer", + "example": 7 + }, + "is_active": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/toggle": { + "post": { + "tags": [ + "Products" + ], + "summary": "제품 활성/비활성 토글", + "description": "제품 활성/비활성 토글", + "operationId": "ede8d1ba69bf7eb54a35d0d58c4426fb", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "토글 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "id": { + "type": "integer", + "example": 101 + }, + "is_active": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom/items": { + "get": { + "tags": [ + "Products-BOM" + ], + "summary": "BOM 항목 목록(제품+자재 병합)", + "description": "BOM 항목 목록", + "operationId": "9dc539b9aeccbbcb1f5da663a5aef032", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BomItem" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom/items/bulk": { + "post": { + "tags": [ + "Products-BOM" + ], + "summary": "BOM 항목 대량 업서트", + "description": "BOM 대량 업서트", + "operationId": "8f946d37a69929d500530c5b5422b6dc", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BomItemBulkUpsertRequest" + } + } + } + }, + "responses": { + "200": { + "description": "업서트 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "created": { + "type": "integer", + "example": 2 + }, + "updated": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom/items/{item}": { + "delete": { + "tags": [ + "Products-BOM" + ], + "summary": "BOM 항목 단건 삭제", + "description": "BOM 단건 삭제", + "operationId": "655db9e8d990062715c6167096ba1249", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "item", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Products-BOM" + ], + "summary": "BOM 항목 단건 수정", + "description": "BOM 단건 수정", + "operationId": "b5996436aac03a202a221866e1724ae8", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "item", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BomItemUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/BomItem" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom/items/reorder": { + "post": { + "tags": [ + "Products-BOM" + ], + "summary": "BOM 정렬 변경", + "description": "BOM 정렬 변경", + "operationId": "2a9d3310d1daf525aa4596a3f42ff676", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BomReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "저장 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom/summary": { + "get": { + "tags": [ + "Products-BOM" + ], + "summary": "BOM 요약", + "description": "BOM 요약(건수/합계 등)", + "operationId": "0e599352e4f181caf80adde87ac8689f", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "요약 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "count": { + "type": "integer", + "example": 5 + }, + "count_product": { + "type": "integer", + "example": 2 + }, + "count_material": { + "type": "integer", + "example": 3 + }, + "quantity_sum": { + "type": "string", + "example": "7.0000" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom/validate": { + "get": { + "tags": [ + "Products-BOM" + ], + "summary": "BOM 유효성 검사", + "description": "BOM 유효성 검사", + "operationId": "776f26c8ab7653942f28af761f099a10", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "검증 결과", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "valid": { + "type": "boolean", + "example": false + }, + "errors": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 11 + }, + "error": { + "type": "string", + "example": "DUPLICATE_ITEM" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom": { + "post": { + "tags": [ + "Products-BOM" + ], + "summary": "BOM 구성 저장(구성 전체 교체)", + "description": "기존 BOM을 모두 삭제하고, 전달된 categories/items 기준으로 다시 저장합니다.", + "operationId": "284001073d532f412a4aca8abe59dcf5", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "상위(모델) 제품 ID", + "required": true, + "schema": { + "type": "integer", + "example": 123 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BomReplaceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "저장 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "BOM 항목이 저장되었습니다." + }, + "data": { + "$ref": "#/components/schemas/BomReplaceResult" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom/categories": { + "get": { + "tags": [ + "Products-BOM" + ], + "summary": "해당 제품에서 사용 중인 BOM 카테고리 목록", + "description": "product_components 테이블에서 해당 제품(parent_product_id)의 카테고리(id/name)를 집계하여 반환합니다.", + "operationId": "56303e10174e44f7fb86700f8d351093", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "상위(모델) 제품 ID", + "required": true, + "schema": { + "type": "integer", + "example": 123 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BomCategoryStat" + } + } + }, + "type": "object" + } + ] + }, + "example": { + "success": true, + "message": "조회 성공", + "data": [ + { + "category_id": 1, + "category_name": "기본", + "count": 5 + }, + { + "category_id": 2, + "category_name": "옵션", + "count": 3 + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/bom/categories": { + "get": { + "tags": [ + "Products-BOM" + ], + "summary": "자주 사용된 BOM 카테고리 추천", + "description": "테넌트 전체 product_components 데이터를 집계해 카테고리 사용 빈도가 높은 순으로 반환합니다. q로 부분 검색 가능합니다.", + "operationId": "ccc33fdaa756e10aaffe943ae8c53e6f", + "parameters": [ + { + "name": "q", + "in": "query", + "description": "카테고리명 부분 검색", + "required": false, + "schema": { + "type": "string", + "example": "기" + } + }, + { + "name": "limit", + "in": "query", + "description": "최대 항목 수(기본 20)", + "required": false, + "schema": { + "type": "integer", + "example": 20 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BomCategoryStat" + } + } + }, + "type": "object" + } + ] + }, + "example": { + "success": true, + "message": "조회 성공", + "data": [ + { + "category_id": 1, + "category_name": "기본", + "count": 127 + }, + { + "category_id": 2, + "category_name": "옵션", + "count": 88 + }, + { + "category_id": null, + "category_name": "패키지", + "count": 12 + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/products/{id}/bom/tree": { + "get": { + "tags": [ + "Products-BOM" + ], + "summary": "제품 BOM 트리 조회(재귀)", + "description": "특정 제품의 하위 구성(제품/자재)을 재귀적으로 트리 형태로 반환합니다. depth로 최대 깊이를 제한합니다(기본 10).", + "operationId": "6c3bcf2518bb78c2e57b3cff785e8de2", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "제품 ID", + "required": true, + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "depth", + "in": "query", + "description": "재귀 깊이(루트=0). 기본 10", + "required": false, + "schema": { + "type": "integer", + "default": 10, + "maximum": 50, + "minimum": 0, + "example": 5 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "product": { + "properties": { + "id": { + "type": "integer" + }, + "code": { + "type": "string" + }, + "name": { + "type": "string" + }, + "unit": { + "type": "string", + "nullable": true + }, + "category_id": { + "type": "integer", + "nullable": true + }, + "product_type": { + "type": "string" + } + }, + "type": "object" + }, + "tree": { + "$ref": "#/components/schemas/BomTreeNode" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "대상 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/purchases": { + "get": { + "tags": [ + "Purchases" + ], + "summary": "매입 목록 조회", + "description": "매입 목록을 조회합니다.", + "operationId": "6328e8d97ba6083bf2e7b85af22de477", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (매입번호, 거래처명, 적요)", + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "draft", + "confirmed" + ] + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "purchase_date", + "enum": [ + "purchase_date", + "total_amount", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Purchase" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Purchases" + ], + "summary": "매입 등록", + "description": "새로운 매입을 등록합니다. 매입번호는 자동 생성됩니다.", + "operationId": "26c6e18ab65f31b177a7fa5ad896f3fd", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PurchaseCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Purchase" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/purchases/summary": { + "get": { + "tags": [ + "Purchases" + ], + "summary": "매입 요약 조회", + "description": "기간별 매입 요약을 조회합니다.", + "operationId": "33f48e74780b1207cffafb1f2592c302", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "draft", + "confirmed" + ] + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PurchaseSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/purchases/dashboard-detail": { + "get": { + "tags": [ + "Purchases" + ], + "summary": "매입 대시보드 상세 조회", + "description": "CEO 대시보드 모달용 매입 상세 데이터를 조회합니다. 당월 요약, 월별 추이, 유형별 분포, 일별 내역을 반환합니다.", + "operationId": "9c4ef6c7a0e64b10bbe3f3c0587109b9", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PurchaseDashboardDetail" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/purchases/{id}": { + "get": { + "tags": [ + "Purchases" + ], + "summary": "매입 상세 조회", + "description": "매입 상세 정보를 조회합니다.", + "operationId": "c169312b0c60e0a39bcb5128c8cfe9f3", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매입 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Purchase" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매입 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Purchases" + ], + "summary": "매입 수정", + "description": "매입 정보를 수정합니다. 임시저장(draft) 상태에서만 수정 가능합니다.", + "operationId": "809858a5b2098c38c53771b050c0747b", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매입 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PurchaseUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Purchase" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 또는 수정 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매입 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Purchases" + ], + "summary": "매입 삭제", + "description": "매입을 삭제합니다. 임시저장(draft) 상태에서만 삭제 가능합니다. (Soft Delete)", + "operationId": "c7479e37feb9ebbb5d4823601e742b2a", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매입 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "삭제 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매입 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/purchases/{id}/confirm": { + "post": { + "tags": [ + "Purchases" + ], + "summary": "매입 확정", + "description": "매입을 확정합니다. 임시저장(draft) 상태에서만 확정 가능합니다.", + "operationId": "1292bc07194f58d85e84ebca40676bc2", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매입 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "확정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Purchase" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "확정 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매입 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/purchases/bulk-update-type": { + "post": { + "tags": [ + "Purchases" + ], + "summary": "매입유형 일괄 변경", + "description": "선택한 매입 건들의 매입유형을 일괄 변경합니다.", + "operationId": "1838797b6657940ff0a07a7cf8d4b81a", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "ids", + "purchase_type" + ], + "properties": { + "ids": { + "description": "매입 ID 목록", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + }, + "purchase_type": { + "description": "매입유형", + "type": "string", + "enum": [ + "unset", + "raw_material", + "subsidiary_material", + "product", + "outsourcing", + "consumables", + "repair", + "transportation", + "office_supplies", + "rent", + "utilities", + "communication", + "vehicle", + "entertainment", + "insurance", + "other_service" + ], + "example": "raw_material" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "updated_count": { + "description": "변경된 건수", + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/purchases/bulk-update-tax-received": { + "post": { + "tags": [ + "Purchases" + ], + "summary": "세금계산서 수취 일괄 설정", + "description": "선택한 매입 건들의 세금계산서 수취 여부를 일괄 설정합니다.", + "operationId": "2dc18ff1dfcc6bd3cccc9fc841af1750", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "ids", + "tax_invoice_received" + ], + "properties": { + "ids": { + "description": "매입 ID 목록", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + }, + "tax_invoice_received": { + "description": "세금계산서 수취 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "설정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "updated_count": { + "description": "변경된 건수", + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/push/register-token": { + "post": { + "tags": [ + "Push" + ], + "summary": "FCM 토큰 등록", + "description": "디바이스의 FCM 토큰을 등록합니다. 동일한 토큰이 이미 존재하면 업데이트됩니다.", + "operationId": "989a9f38e51c862c65ec5b2c26a660be", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterTokenRequest" + } + } + } + }, + "responses": { + "200": { + "description": "토큰 등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "푸시 토큰이 등록되었습니다." + }, + "data": { + "$ref": "#/components/schemas/PushDeviceToken" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/push/unregister-token": { + "post": { + "tags": [ + "Push" + ], + "summary": "FCM 토큰 해제", + "description": "디바이스의 FCM 토큰을 비활성화합니다.", + "operationId": "de90137782ac3cf9c6af1afcda35b16a", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnregisterTokenRequest" + } + } + } + }, + "responses": { + "200": { + "description": "토큰 해제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "푸시 토큰이 해제되었습니다." + }, + "data": { + "properties": { + "unregistered": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "토큰 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/push/tokens": { + "get": { + "tags": [ + "Push" + ], + "summary": "사용자 토큰 목록 조회", + "description": "현재 사용자의 활성화된 디바이스 토큰 목록을 조회합니다.", + "operationId": "fe50aeff0121d07d46c0a2385ea94da2", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushDeviceToken" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/push/settings": { + "get": { + "tags": [ + "Push" + ], + "summary": "알림 설정 조회", + "description": "현재 사용자의 알림 유형별 설정을 조회합니다. 설정이 없는 유형은 기본값으로 반환됩니다.", + "operationId": "dc0ada12ab1b07bfac0315b0a8f9f7ab", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "description": "알림 유형별 설정 (키: notification_type)", + "properties": { + "deposit": { + "$ref": "#/components/schemas/PushNotificationSetting" + }, + "withdrawal": { + "$ref": "#/components/schemas/PushNotificationSetting" + }, + "order": { + "$ref": "#/components/schemas/PushNotificationSetting" + }, + "approval": { + "$ref": "#/components/schemas/PushNotificationSetting" + }, + "attendance": { + "$ref": "#/components/schemas/PushNotificationSetting" + }, + "notice": { + "$ref": "#/components/schemas/PushNotificationSetting" + }, + "system": { + "$ref": "#/components/schemas/PushNotificationSetting" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Push" + ], + "summary": "알림 설정 업데이트", + "description": "사용자의 알림 설정을 업데이트합니다. 여러 알림 유형을 한 번에 설정할 수 있습니다.", + "operationId": "c95d6aa1bc503f882a1484a50ff16ef2", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePushSettingsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "설정 업데이트 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "알림 설정이 업데이트되었습니다." + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushNotificationSetting" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/push/notification-types": { + "get": { + "tags": [ + "Push" + ], + "summary": "알림 유형 목록 조회", + "description": "지원하는 알림 유형과 알림음 목록을 조회합니다.", + "operationId": "4ede80e695420b8c9f80d456c9a57d03", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/NotificationTypesResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes": { + "get": { + "tags": [ + "Quote" + ], + "summary": "견적 목록 조회", + "operationId": "82ac3b11d1dcef2b7064b43c24778f1d", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "q", + "in": "query", + "description": "검색어", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "draft", + "sent", + "approved", + "rejected", + "finalized", + "converted" + ] + } + }, + { + "name": "product_category", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "SCREEN", + "STEEL" + ] + } + }, + { + "name": "client_id", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "date_from", + "in": "query", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "date_to", + "in": "query", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "sort_by", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sort_order", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ] + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/QuotePagination" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Quote" + ], + "summary": "견적 생성", + "operationId": "27bcbb099432b853d3a4a91030c297a3", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuoteCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Quote" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}": { + "get": { + "tags": [ + "Quote" + ], + "summary": "견적 상세 조회", + "operationId": "e86828ba7568ca7cdeb05a857281a92d", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Quote" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "견적 없음" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Quote" + ], + "summary": "견적 수정", + "operationId": "4a3bdb36c509c8fa0d8be4544c621bed", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuoteUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Quote" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "수정 불가 상태" + }, + "404": { + "description": "견적 없음" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Quote" + ], + "summary": "견적 삭제", + "operationId": "2c61ff50bf238605bcb26e31af0365b0", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공" + }, + "400": { + "description": "삭제 불가 상태" + }, + "404": { + "description": "견적 없음" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/bulk": { + "delete": { + "tags": [ + "Quote" + ], + "summary": "견적 일괄 삭제", + "operationId": "2cb260b6bdf3d0b7ab43a499d93f4806", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "deleted_count": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}/finalize": { + "post": { + "tags": [ + "Quote" + ], + "summary": "견적 확정", + "operationId": "3085281f5b1966c8eb8a4f88215eeee0", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Quote" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "확정 불가 상태" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}/cancel-finalize": { + "post": { + "tags": [ + "Quote" + ], + "summary": "견적 확정 취소", + "operationId": "a89b46f8d6b4366d8d39583f4bc4b31c", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Quote" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "취소 불가 상태" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}/convert": { + "post": { + "tags": [ + "Quote" + ], + "summary": "수주 전환", + "operationId": "905dd95c0b3651400a6ce30a52107192", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/Quote" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "전환 불가 상태" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/number/preview": { + "get": { + "tags": [ + "Quote" + ], + "summary": "견적번호 미리보기", + "operationId": "9815bdc6b377335f8dd9b7017ff74188", + "parameters": [ + { + "name": "product_category", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "SCREEN", + "STEEL" + ] + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/QuoteNumberPreview" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/calculation/schema": { + "get": { + "tags": [ + "Quote" + ], + "summary": "자동산출 입력 스키마 조회", + "operationId": "ad2429664e7f274203988a9cf00fee85", + "parameters": [ + { + "name": "product_category", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "SCREEN", + "STEEL" + ] + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "description": "제품별 입력 스키마", + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/calculate": { + "post": { + "tags": [ + "Quote" + ], + "summary": "자동산출 실행", + "operationId": "a0b24ede12ae615f82cf290b39a90056", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuoteCalculateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/QuoteCalculationResult" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/calculate/bom": { + "post": { + "tags": [ + "Quote" + ], + "summary": "BOM 기반 자동산출 (10단계 디버깅)", + "description": "완제품 코드와 입력 변수를 받아 BOM 기반으로 품목/단가/금액을 자동 계산합니다. MNG FormulaEvaluatorService와 동일한 10단계 디버깅을 지원합니다.", + "operationId": "4912d1699e7da3e31cab601752325f86", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuoteBomCalculateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "산출 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "견적이 산출되었습니다." + }, + "data": { + "$ref": "#/components/schemas/QuoteBomCalculationResult" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "유효성 검증 실패" + }, + "401": { + "description": "인증 필요" + }, + "404": { + "description": "완제품 코드 없음" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/calculate/bom/bulk": { + "post": { + "tags": [ + "Quote" + ], + "summary": "다건 BOM 기반 자동산출", + "description": "여러 품목의 완제품 코드와 입력 변수를 받아 BOM 기반으로 일괄 계산합니다. React QuoteFormItem 필드명(camelCase)과 API 변수명(약어) 모두 지원합니다.", + "operationId": "ab5c1a8f39fd60ea8d1bb13d3e05a649", + "requestBody": { + "description": "품목 배열과 디버그 옵션", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuoteBomBulkCalculateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "산출 성공 (부분 실패 포함 가능)", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "견적이 일괄 산출되었습니다." + }, + "data": { + "$ref": "#/components/schemas/QuoteBomBulkCalculationResult" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "유효성 검증 실패 (items 배열 누락 등)" + }, + "401": { + "description": "인증 필요" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}/pdf": { + "post": { + "tags": [ + "Quote" + ], + "summary": "견적서 PDF 생성", + "operationId": "8695ae7c229ebb9457ae23635b8b41c6", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "quote_id": { + "type": "integer" + }, + "quote_number": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "path": { + "type": "string" + }, + "generated_at": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}/send/email": { + "post": { + "tags": [ + "Quote" + ], + "summary": "견적서 이메일 발송", + "operationId": "c19c79cb7d87b69a3eb639a81b2953d3", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuoteSendEmailRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "success": { + "type": "boolean" + }, + "send_log": { + "type": "object" + }, + "quote_status": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "수신자 정보 없음" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}/send/kakao": { + "post": { + "tags": [ + "Quote" + ], + "summary": "견적서 카카오톡 발송", + "operationId": "63ff336459cb8e1e26274951c44fafc8", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuoteSendKakaoRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "success": { + "type": "boolean" + }, + "send_log": { + "type": "object" + }, + "quote_status": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "수신자 정보 없음" + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/quotes/{id}/send/history": { + "get": { + "tags": [ + "Quote" + ], + "summary": "발송 이력 조회", + "operationId": "30fdd2dac9a56408dc5e61e535d39bc0", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "properties": { + "quote_id": { + "type": "integer" + }, + "quote_number": { + "type": "string" + }, + "history": { + "type": "array", + "items": { + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/receivables": { + "get": { + "tags": [ + "Receivables" + ], + "summary": "채권 현황 목록 조회", + "description": "거래처별 월별 매출, 입금, 어음, 미수금 현황을 조회합니다.", + "operationId": "getReceivablesList", + "parameters": [ + { + "name": "year", + "in": "query", + "description": "조회 연도", + "schema": { + "type": "integer", + "example": 2025 + } + }, + { + "name": "search", + "in": "query", + "description": "거래처명 검색", + "schema": { + "type": "string", + "example": "삼성" + } + }, + { + "name": "has_receivable", + "in": "query", + "description": "미수금이 있는 거래처만 조회", + "schema": { + "type": "boolean", + "example": true + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VendorReceivables" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/receivables/summary": { + "get": { + "tags": [ + "Receivables" + ], + "summary": "채권 현황 요약 통계", + "description": "연도별 총 매출, 입금, 어음, 미수금 합계 및 거래처 통계를 조회합니다.", + "operationId": "getReceivablesSummary", + "parameters": [ + { + "name": "year", + "in": "query", + "description": "조회 연도", + "schema": { + "type": "integer", + "example": 2025 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/ReceivablesSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/receivings": { + "get": { + "tags": [ + "Receivings" + ], + "summary": "입고 목록 조회", + "description": "입고 목록을 조회합니다.", + "operationId": "3afb15885e8a9802f58ecb86d5608523", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (발주번호, 품목코드, 품목명, 공급업체)", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 (receiving_pending 선택시 inspection_pending도 포함)", + "schema": { + "type": "string", + "enum": [ + "order_completed", + "shipping", + "inspection_pending", + "receiving_pending", + "completed" + ] + } + }, + { + "name": "start_date", + "in": "query", + "description": "입고일 시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "입고일 종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "receiving_date", + "due_date", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Receiving" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Receivings" + ], + "summary": "입고 등록", + "description": "새로운 입고를 등록합니다. 입고번호는 자동 생성됩니다.", + "operationId": "1d822f02d4d7847dceea3e69aa3c5783", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReceivingCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Receiving" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/receivings/stats": { + "get": { + "tags": [ + "Receivings" + ], + "summary": "입고 통계 조회", + "description": "입고 현황 통계를 조회합니다.", + "operationId": "921e16b8b3ff4d8311bba292d9d0ad84", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ReceivingStats" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/receivings/{id}": { + "get": { + "tags": [ + "Receivings" + ], + "summary": "입고 상세 조회", + "description": "입고 상세 정보를 조회합니다.", + "operationId": "3f4205ae1c1e1216d34d789aeba19e69", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "입고 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Receiving" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "입고 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Receivings" + ], + "summary": "입고 수정", + "description": "입고 정보를 수정합니다. 입고완료(completed) 상태에서는 수정 불가합니다.", + "operationId": "4447efe8def204719d9c57c5d99bf21e", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "입고 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReceivingUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Receiving" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 또는 수정 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "입고 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Receivings" + ], + "summary": "입고 삭제", + "description": "입고를 삭제합니다. 입고완료(completed) 상태에서는 삭제 불가합니다. (Soft Delete)", + "operationId": "950eab629a9a0d03e313bb68dc9c8c62", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "입고 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "삭제 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "입고 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/receivings/{id}/process": { + "post": { + "tags": [ + "Receivings" + ], + "summary": "입고처리", + "description": "입고를 처리합니다. 입고수량, 입고위치, LOT번호 등을 입력하고 상태를 '입고완료'로 변경합니다.", + "operationId": "943712d12152e28ae4a0dd3120021c23", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "입고 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReceivingProcessRequest" + } + } + } + }, + "responses": { + "200": { + "description": "입고처리 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Receiving" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "입고처리 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "입고 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/refresh": { + "post": { + "tags": [ + "Auth" + ], + "summary": "토큰 갱신 (리프레시 토큰으로 새로운 액세스 토큰 발급)", + "description": "리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 발급받습니다. 리프레시 토큰은 사용 후 폐기되며 새로운 리프레시 토큰이 발급됩니다.", + "operationId": "025d45031d3459003752d08ffa008936", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "refresh_token" + ], + "properties": { + "refresh_token": { + "description": "리프레시 토큰", + "type": "string", + "example": "2|def456uvw789" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "토큰 갱신 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "토큰이 갱신되었습니다" + }, + "access_token": { + "description": "새로운 액세스 토큰", + "type": "string", + "example": "3|ghi789rst012" + }, + "refresh_token": { + "description": "새로운 리프레시 토큰", + "type": "string", + "example": "4|jkl012mno345" + }, + "token_type": { + "description": "토큰 타입", + "type": "string", + "example": "Bearer" + }, + "expires_in": { + "description": "액세스 토큰 만료 시간 (초 단위, null이면 무제한)", + "type": "integer", + "example": 7200, + "nullable": true + }, + "expires_at": { + "description": "액세스 토큰 만료 시각 (null이면 무제한)", + "type": "string", + "example": "2025-11-10 18:00:00", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "리프레시 토큰이 유효하지 않거나 만료됨", + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "type": "string", + "example": "리프레시 토큰이 유효하지 않거나 만료되었습니다" + }, + "error_code": { + "description": "에러 코드", + "type": "string", + "example": "TOKEN_EXPIRED" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/register": { + "post": { + "tags": [ + "Auth" + ], + "summary": "회원가입 및 테넌트 생성", + "description": "신규 회원가입과 동시에 새로운 테넌트(회사)를 생성합니다. 사용자는 자동으로 system_manager 역할이 부여되며 모든 테넌트 메뉴 권한을 갖습니다.", + "operationId": "register", + "requestBody": { + "description": "회원가입 정보", + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "user_id", + "name", + "email", + "password", + "password_confirmation", + "company_name", + "business_num" + ], + "properties": { + "user_id": { + "description": "사용자 아이디 (영문, 숫자, _, - 만 허용)", + "type": "string", + "example": "john_doe" + }, + "name": { + "description": "사용자 이름", + "type": "string", + "example": "홍길동" + }, + "email": { + "description": "이메일 주소", + "type": "string", + "format": "email", + "example": "john@example.com" + }, + "phone": { + "description": "전화번호 (선택)", + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "password": { + "description": "비밀번호 (최소 8자)", + "type": "string", + "format": "password", + "example": "password123!" + }, + "password_confirmation": { + "description": "비밀번호 확인", + "type": "string", + "format": "password", + "example": "password123!" + }, + "position": { + "description": "직책 (선택)", + "type": "string", + "example": "개발팀장", + "nullable": true + }, + "company_name": { + "description": "회사명", + "type": "string", + "example": "(주)테크컴퍼니" + }, + "business_num": { + "description": "사업자등록번호 (000-00-00000 형식)", + "type": "string", + "example": "123-45-67890" + }, + "company_scale": { + "description": "회사 규모 (선택)", + "type": "string", + "example": "중소기업", + "nullable": true + }, + "industry": { + "description": "업종 (선택)", + "type": "string", + "example": "IT/소프트웨어", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "회원가입 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "회원가입이 완료되었습니다" + }, + "data": { + "properties": { + "user": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "string", + "example": "john_doe" + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "john@example.com" + }, + "phone": { + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "options": { + "properties": { + "position": { + "type": "string", + "example": "개발팀장" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "tenant": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "company_name": { + "type": "string", + "example": "(주)테크컴퍼니" + }, + "business_num": { + "type": "string", + "example": "123-45-67890" + }, + "tenant_st_code": { + "description": "테넌트 상태 (trial: 데모, active: 정식, none: 비활성)", + "type": "string", + "example": "trial" + }, + "options": { + "properties": { + "company_scale": { + "type": "string", + "example": "중소기업" + }, + "industry": { + "type": "string", + "example": "IT/소프트웨어" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "menus": { + "description": "생성된 테넌트의 기본 메뉴 목록 (9개: 대시보드, 기초정보관리, 제품관리, 거래처관리, BOM관리, 시스템관리, 사용자관리, 권한관리, 부서관리)", + "type": "array", + "items": { + "properties": { + "id": { + "description": "메뉴 ID", + "type": "integer", + "example": 1 + }, + "parent_id": { + "description": "상위 메뉴 ID (최상위 메뉴는 null)", + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "description": "메뉴명", + "type": "string", + "example": "대시보드" + }, + "url": { + "description": "메뉴 URL", + "type": "string", + "example": "/dashboard" + }, + "icon": { + "description": "메뉴 아이콘", + "type": "string", + "example": "dashboard" + }, + "sort_order": { + "description": "정렬 순서", + "type": "integer", + "example": 1 + }, + "is_external": { + "description": "외부 링크 여부 (0: 내부, 1: 외부)", + "type": "integer", + "example": 0 + }, + "external_url": { + "description": "외부 링크 URL", + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + } + }, + "roles": { + "description": "생성된 역할 목록 (시스템 관리자 역할 1개)", + "type": "array", + "items": { + "properties": { + "id": { + "description": "역할 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "역할명", + "type": "string", + "example": "system_manager" + }, + "description": { + "description": "역할 설명", + "type": "string", + "example": "시스템 관리자" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "유효성 검증에 실패했습니다" + }, + "errors": { + "properties": { + "user_id": { + "type": "array", + "items": { + "type": "string", + "example": "이미 사용 중인 아이디입니다" + } + }, + "business_num": { + "type": "array", + "items": { + "type": "string", + "example": "사업자등록번호 형식이 올바르지 않습니다 (000-00-00000)" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "500": { + "description": "서버 오류", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "회원가입 처리 중 오류가 발생했습니다" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/reports/daily": { + "get": { + "tags": [ + "Reports" + ], + "summary": "일일 일보 조회", + "description": "매일 전일의 입출금 및 매출 매입 현황을 자동 집계합니다.", + "operationId": "2b52cd3062a01d839fbd5651a6509699", + "parameters": [ + { + "name": "date", + "in": "query", + "description": "기준일 (YYYY-MM-DD, 기본값: 오늘)", + "required": false, + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-15" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/DailyReport" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + }, + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/reports/daily/export": { + "get": { + "tags": [ + "Reports" + ], + "summary": "일일 일보 엑셀 다운로드", + "description": "일일 일보를 엑셀 파일로 다운로드합니다.", + "operationId": "7d160b5be3e708fb1c92165e14b5291f", + "parameters": [ + { + "name": "date", + "in": "query", + "description": "기준일 (YYYY-MM-DD, 기본값: 오늘)", + "required": false, + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-15" + } + } + ], + "responses": { + "200": { + "description": "엑셀 파일", + "content": { + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + }, + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/reports/expense-estimate": { + "get": { + "tags": [ + "Reports" + ], + "summary": "지출 예상 내역서 조회", + "description": "예상 지출 금액 및 일정을 조회합니다.", + "operationId": "c617a94b5734b5e3e239f3dee061a3a7", + "parameters": [ + { + "name": "year_month", + "in": "query", + "description": "기준 연월 (YYYY-MM, 기본값: 이번달)", + "required": false, + "schema": { + "type": "string", + "example": "2025-01" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/ExpenseEstimate" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + }, + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/reports/expense-estimate/export": { + "get": { + "tags": [ + "Reports" + ], + "summary": "지출 예상 내역서 엑셀 다운로드", + "description": "지출 예상 내역서를 엑셀 파일로 다운로드합니다.", + "operationId": "a16ff50bce1523e2f152814a5680b15a", + "parameters": [ + { + "name": "year_month", + "in": "query", + "description": "기준 연월 (YYYY-MM, 기본값: 이번달)", + "required": false, + "schema": { + "type": "string", + "example": "2025-01" + } + } + ], + "responses": { + "200": { + "description": "엑셀 파일", + "content": { + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "BearerAuth": [] + }, + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/roles": { + "get": { + "tags": [ + "Role" + ], + "summary": "역할 목록 조회", + "description": "테넌트 범위 내 역할 목록을 페이징으로 반환합니다. (q로 이름/설명 검색)", + "operationId": "2fe3440eb56182754caf817600b13375", + "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "example": 10 + } + }, + { + "name": "q", + "in": "query", + "required": false, + "schema": { + "type": "string", + "example": "read" + } + } + ], + "responses": { + "200": { + "description": "목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "per_page": { + "type": "integer", + "example": 10 + }, + "total": { + "type": "integer", + "example": 2 + }, + "data": { + "$ref": "#/components/schemas/RoleList" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Role" + ], + "summary": "역할 생성", + "description": "새로운 역할을 생성합니다.", + "operationId": "137c09897991824572c39bbef8ee85ef", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoleCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Role" + } + }, + "type": "object" + } + ] + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/roles/{id}": { + "get": { + "tags": [ + "Role" + ], + "summary": "역할 단건 조회", + "description": "ID로 역할 상세를 조회합니다.", + "operationId": "f7844d6fdc979ad0811cc55059a7aabf", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "responses": { + "200": { + "description": "단건 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Role" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Role" + ], + "summary": "역할 삭제", + "description": "지정한 역할을 삭제합니다.", + "operationId": "5ce8deb4dabfaeb888d86d328478f40c", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Role" + ], + "summary": "역할 수정", + "description": "기존 역할 정보를 부분 수정합니다.", + "operationId": "6e5662bbe051b78ef095bbb4885fa392", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "example": 3 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoleUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Role" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/roles/{id}/permissions": { + "get": { + "tags": [ + "RolePermission" + ], + "summary": "역할의 퍼미션 목록 조회", + "description": "해당 역할에 현재 부여된 퍼미션 목록을 반환합니다.", + "operationId": "06d579f4daa2119810017c03f0a55350", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 3 + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PermissionList" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "역할 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "RolePermission" + ], + "summary": "역할에 퍼미션 부여", + "description": "퍼미션 이름 배열 또는 메뉴ID+액션 조합으로 역할에 권한을 부여합니다.", + "operationId": "d0c6c69cf73d38115a7ac9a53d585fe2", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 3 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolePermissionGrantRequest" + } + } + } + }, + "responses": { + "200": { + "description": "부여 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "역할/퍼미션 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "RolePermission" + ], + "summary": "역할에서 퍼미션 회수", + "description": "퍼미션 이름 배열 또는 메뉴ID+액션 조합으로 권한을 회수합니다.", + "operationId": "373fb4fa8fb9b1cffd43296fcb6a9252", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 3 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolePermissionRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "회수 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "역할/퍼미션 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/roles/{id}/permissions/sync": { + "put": { + "tags": [ + "RolePermission" + ], + "summary": "역할의 퍼미션 동기화(교체)", + "description": "전달된 목록으로 역할의 권한을 완전히 교체합니다.", + "operationId": "dff84cb79d7100d55cd5036d450afcf7", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 3 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolePermissionSyncRequest" + } + } + } + }, + "responses": { + "200": { + "description": "동기화 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "역할/퍼미션 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sales": { + "get": { + "tags": [ + "Sales" + ], + "summary": "매출 목록 조회", + "description": "매출 목록을 조회합니다.", + "operationId": "4589943f22b258faef10d690dd53a47c", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (매출번호, 거래처명, 적요)", + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "draft", + "confirmed", + "invoiced" + ] + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "sale_date", + "enum": [ + "sale_date", + "total_amount", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Sale" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Sales" + ], + "summary": "매출 등록", + "description": "새로운 매출을 등록합니다. 매출번호는 자동 생성됩니다.", + "operationId": "bdaa539a642425fb4e7e247439f8af90", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaleCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Sale" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sales/summary": { + "get": { + "tags": [ + "Sales" + ], + "summary": "매출 요약 조회", + "description": "기간별 매출 요약을 조회합니다.", + "operationId": "a654f9f21749cf00d622ec4d74730682", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "draft", + "confirmed", + "invoiced" + ] + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/SaleSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sales/{id}": { + "get": { + "tags": [ + "Sales" + ], + "summary": "매출 상세 조회", + "description": "매출 상세 정보를 조회합니다.", + "operationId": "d05a641ae26c22d781f4f7bcf1b540b7", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매출 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Sale" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매출 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Sales" + ], + "summary": "매출 수정", + "description": "매출 정보를 수정합니다. 임시저장(draft) 상태에서만 수정 가능합니다.", + "operationId": "b8e8cb979b6c1364788b59a3383c99de", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매출 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaleUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Sale" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 또는 수정 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매출 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Sales" + ], + "summary": "매출 삭제", + "description": "매출을 삭제합니다. 임시저장(draft) 상태에서만 삭제 가능합니다. (Soft Delete)", + "operationId": "0508b3f18fdace0a41b0290596523d1f", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매출 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "삭제 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매출 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sales/{id}/confirm": { + "post": { + "tags": [ + "Sales" + ], + "summary": "매출 확정", + "description": "매출을 확정합니다. 임시저장(draft) 상태에서만 확정 가능합니다.", + "operationId": "2a43041427f693a4b52a70bcd42b8bee", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매출 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "확정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Sale" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "확정 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매출 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sales/{id}/statement": { + "get": { + "tags": [ + "Sales" + ], + "summary": "거래명세서 조회", + "description": "매출에 대한 거래명세서 정보를 조회합니다.", + "operationId": "e8830992269fc5c6dd930b11bc6e6887", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매출 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/SaleStatement" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매출 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sales/{id}/statement/issue": { + "post": { + "tags": [ + "Sales" + ], + "summary": "거래명세서 발행", + "description": "매출에 대한 거래명세서를 발행합니다. 확정(confirmed) 상태의 매출만 발행 가능합니다.", + "operationId": "f1134ca9dba52fa4f2be780ef24d8544", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매출 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "발행 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/SaleStatementIssueResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "발행 불가 (미확정 상태)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매출 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sales/{id}/statement/send": { + "post": { + "tags": [ + "Sales" + ], + "summary": "거래명세서 이메일 발송", + "description": "거래명세서를 이메일로 발송합니다. 이메일 미입력 시 거래처 이메일로 발송됩니다.", + "operationId": "6b5fcb977514c53c268639b0afbe7c07", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "매출 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaleStatementSendRequest" + } + } + } + }, + "responses": { + "200": { + "description": "발송 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/SaleStatementSendResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "발송 불가 (이메일 없음)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "매출 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sales/bulk-issue-statement": { + "post": { + "tags": [ + "Sales" + ], + "summary": "거래명세서 일괄 발행", + "description": "여러 매출에 대한 거래명세서를 일괄 발행합니다. 확정(confirmed) 상태이면서 아직 발행되지 않은 건만 발행됩니다. 각 건별로 성공/실패가 처리됩니다.", + "operationId": "a5484d4235420ccb12dfdda6d22edbb0", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaleBulkIssueStatementRequest" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 발행 처리 완료", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/SaleBulkIssueStatementResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/shipments": { + "get": { + "tags": [ + "Shipments" + ], + "summary": "출하 목록 조회", + "description": "출하 목록을 조회합니다.", + "operationId": "89660d5bddd8277b3d1afe377035fd98", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (출하번호, LOT번호, 발주처명, 현장명)", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "scheduled", + "ready", + "shipping", + "completed" + ] + } + }, + { + "name": "priority", + "in": "query", + "description": "우선순위", + "schema": { + "type": "string", + "enum": [ + "urgent", + "normal", + "low" + ] + } + }, + { + "name": "delivery_method", + "in": "query", + "description": "배송방식", + "schema": { + "type": "string", + "enum": [ + "pickup", + "direct", + "logistics" + ] + } + }, + { + "name": "scheduled_from", + "in": "query", + "description": "예정일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "scheduled_to", + "in": "query", + "description": "예정일 종료", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "can_ship", + "in": "query", + "description": "출하가능 여부", + "schema": { + "type": "boolean" + } + }, + { + "name": "deposit_confirmed", + "in": "query", + "description": "입금확인 여부", + "schema": { + "type": "boolean" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "scheduled_date", + "enum": [ + "scheduled_date", + "shipment_no", + "customer_name", + "priority" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipmentWithItems" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 100 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Shipments" + ], + "summary": "출하 생성", + "description": "새 출하를 생성합니다.", + "operationId": "9aa1e6c234252448219e322a2bdceda6", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShipmentStoreRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ShipmentWithItems" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/shipments/stats": { + "get": { + "tags": [ + "Shipments" + ], + "summary": "출하 통계 조회", + "description": "전체 출하 통계를 조회합니다.", + "operationId": "b00747a6e3be2fe81adb532c8a91847d", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ShipmentStats" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/shipments/stats-by-status": { + "get": { + "tags": [ + "Shipments" + ], + "summary": "상태별 출하 통계 조회", + "description": "상태별 출하 통계를 조회합니다 (탭용).", + "operationId": "52798044ba13d681ad18a5b47b266579", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ShipmentStatsByStatus" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/shipments/{id}": { + "get": { + "tags": [ + "Shipments" + ], + "summary": "출하 상세 조회", + "description": "출하 상세 정보를 조회합니다. 품목 목록이 포함됩니다.", + "operationId": "58d5d412847e7ce846d4fbba4696c7df", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "출하 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ShipmentWithItems" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "출하 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Shipments" + ], + "summary": "출하 수정", + "description": "출하 정보를 수정합니다.", + "operationId": "4ce0fb9c6ef8398538d34b162e78e8ee", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "출하 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShipmentStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ShipmentWithItems" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "출하 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Shipments" + ], + "summary": "출하 삭제", + "description": "출하를 삭제합니다.", + "operationId": "a12a8aafe54b7f013bff47fcdd66c1b8", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "출하 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "출하 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/shipments/{id}/status": { + "patch": { + "tags": [ + "Shipments" + ], + "summary": "출하 상태 변경", + "description": "출하 상태를 변경합니다.", + "operationId": "3fdcbdbef6eef2764e1c644df2754331", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "출하 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShipmentUpdateStatusRequest" + } + } + } + }, + "responses": { + "200": { + "description": "상태 변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/ShipmentWithItems" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "출하 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/shipments/options/lots": { + "get": { + "tags": [ + "Shipments" + ], + "summary": "LOT 옵션 조회", + "description": "출고 가능한 LOT 목록을 조회합니다.", + "operationId": "88e9e87c461d53db78f9dab1b941e1a5", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LotOption" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/shipments/options/logistics": { + "get": { + "tags": [ + "Shipments" + ], + "summary": "물류사 옵션 조회", + "description": "물류사 목록을 조회합니다.", + "operationId": "583a19588c1a0f2fef90a38f73f3c2cd", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "properties": { + "value": { + "type": "string", + "example": "CJ대한통운" + }, + "label": { + "type": "string", + "example": "CJ대한통운" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/shipments/options/vehicle-tonnage": { + "get": { + "tags": [ + "Shipments" + ], + "summary": "차량 톤수 옵션 조회", + "description": "차량 톤수 목록을 조회합니다.", + "operationId": "02c1d8222967082f168b8083a9653370", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "properties": { + "value": { + "type": "string", + "example": "5톤" + }, + "label": { + "type": "string", + "example": "5톤" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sites": { + "get": { + "tags": [ + "Sites" + ], + "summary": "현장 목록 조회", + "description": "현장 목록을 조회합니다.", + "operationId": "0af4a0e1ae48ca6bb16f1eb900a6a200", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (현장명, 주소)", + "schema": { + "type": "string" + } + }, + { + "name": "is_active", + "in": "query", + "description": "활성화 상태 필터", + "schema": { + "type": "boolean" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "name", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Site" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Sites" + ], + "summary": "현장 등록", + "description": "새로운 현장을 등록합니다.", + "operationId": "b3136ceb32d6b4c90c13d30712744678", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SiteCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Site" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sites/active": { + "get": { + "tags": [ + "Sites" + ], + "summary": "활성화된 현장 목록 (셀렉트박스용)", + "description": "활성화된 현장 목록을 간단한 형태로 조회합니다.", + "operationId": "573531c7039e50448c4fe21ea3bc4b7c", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SiteListItem" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/sites/{id}": { + "get": { + "tags": [ + "Sites" + ], + "summary": "현장 상세 조회", + "description": "현장 상세 정보를 조회합니다.", + "operationId": "542df1ff64c7caddb1d9c7e0b4d9db12", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "현장 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Site" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "현장 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Sites" + ], + "summary": "현장 수정", + "description": "현장 정보를 수정합니다.", + "operationId": "06dc51031e6997d0ec728259f1f01f80", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "현장 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SiteUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Site" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "현장 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Sites" + ], + "summary": "현장 삭제", + "description": "현장을 삭제합니다. (Soft Delete)", + "operationId": "a56189742641b7173f0ef73f00b74db9", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "현장 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "현장 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/stats/summary": { + "get": { + "tags": [ + "Stats" + ], + "summary": "대시보드 통계 요약", + "description": "sam_stat DB 기반 대시보드 요약 통계를 반환합니다. 오늘의 매출/재무/생산 통계, 이번 달 매출 요약, 미해결 알림을 포함합니다. Redis 캐싱 적용 (TTL 5분).", + "operationId": "getStatSummary", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/StatDashboardSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/stats/daily": { + "get": { + "tags": [ + "Stats" + ], + "summary": "도메인별 일간 통계 조회", + "description": "지정한 도메인의 일간 통계를 기간별로 조회합니다. 7개 도메인 지원: sales, finance, production, inventory, quote, hr, system. Redis 캐싱 적용 (TTL 5분).", + "operationId": "getStatDaily", + "parameters": [ + { + "name": "domain", + "in": "query", + "description": "통계 도메인", + "required": true, + "schema": { + "type": "string", + "enum": [ + "sales", + "finance", + "production", + "inventory", + "quote", + "hr", + "system" + ] + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작 날짜", + "required": true, + "schema": { + "type": "string", + "format": "date", + "example": "2026-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료 날짜 (start_date 이후)", + "required": true, + "schema": { + "type": "string", + "format": "date", + "example": "2026-01-31" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "type": "array", + "items": { + "description": "도메인별 일간 통계 레코드 (스키마는 도메인에 따라 다름)", + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/stats/monthly": { + "get": { + "tags": [ + "Stats" + ], + "summary": "도메인별 월간 통계 조회", + "description": "지정한 도메인의 월간 통계를 조회합니다. 4개 도메인 지원: sales, finance, production, project. Redis 캐싱 적용 (TTL 5분).", + "operationId": "getStatMonthly", + "parameters": [ + { + "name": "domain", + "in": "query", + "description": "통계 도메인", + "required": true, + "schema": { + "type": "string", + "enum": [ + "sales", + "finance", + "production", + "project" + ] + } + }, + { + "name": "year", + "in": "query", + "description": "조회 연도", + "required": true, + "schema": { + "type": "integer", + "maximum": 2099, + "minimum": 2020, + "example": 2026 + } + }, + { + "name": "month", + "in": "query", + "description": "조회 월 (미지정 시 연간 전체)", + "required": false, + "schema": { + "type": "integer", + "maximum": 12, + "minimum": 1, + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "type": "array", + "items": { + "description": "도메인별 월간 통계 레코드 (스키마는 도메인에 따라 다름)", + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/stats/alerts": { + "get": { + "tags": [ + "Stats" + ], + "summary": "통계 알림 목록 조회", + "description": "통계 시스템에서 발생한 알림을 조회합니다. 집계 실패, 데이터 누락, 정합성 불일치 등의 알림이 포함됩니다.", + "operationId": "getStatAlerts", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "조회 건수 (기본 20)", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "example": 20 + } + }, + { + "name": "unread_only", + "in": "query", + "description": "미읽은 알림만 조회", + "required": false, + "schema": { + "type": "boolean", + "example": true + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StatAlert" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/status-board/summary": { + "get": { + "tags": [ + "StatusBoard" + ], + "summary": "현황판 요약 조회", + "description": "CEO 대시보드 현황판의 주요 업무 현황 카드 데이터를 조회합니다.\n\n * 포함 항목:\n * - 수주: 오늘 신규 확정 수주 건수\n * - 채권 추심: 추심 진행 중인 건수\n * - 안전 재고: 안전재고 미달 품목 수 (강조 표시)\n * - 세금 신고: 부가세 신고 D-day (7일 이내 강조)\n * - 신규 업체 등록: 최근 7일 신규 거래처 수\n * - 연차: 오늘 휴가 중인 인원 수\n * - 발주: 발주 대기 건수\n * - 결재 요청: 나의 결재 대기 건수 (강조 표시)", + "operationId": "getStatusBoardSummary", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "$ref": "#/components/schemas/StatusBoardSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "인증이 필요합니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/stocks": { + "get": { + "tags": [ + "Stocks" + ], + "summary": "재고 목록 조회", + "description": "재고 현황 목록을 조회합니다.", + "operationId": "282219cac35c11b3fd4b4b0f064500ea", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (품목코드, 품목명)", + "schema": { + "type": "string" + } + }, + { + "name": "item_type", + "in": "query", + "description": "품목유형", + "schema": { + "type": "string", + "enum": [ + "raw_material", + "bent_part", + "purchased_part", + "sub_material", + "consumable" + ] + } + }, + { + "name": "status", + "in": "query", + "description": "재고상태", + "schema": { + "type": "string", + "enum": [ + "normal", + "low", + "out" + ] + } + }, + { + "name": "location", + "in": "query", + "description": "위치 (부분 일치)", + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "item_code", + "enum": [ + "item_code", + "item_name", + "stock_qty", + "oldest_lot_date" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "asc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Stock" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 150 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/stocks/stats": { + "get": { + "tags": [ + "Stocks" + ], + "summary": "재고 통계 조회", + "description": "전체 재고 현황 통계를 조회합니다.", + "operationId": "787454c4385d0a755d3cd4bc0031e851", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/StockStats" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/stocks/stats-by-type": { + "get": { + "tags": [ + "Stocks" + ], + "summary": "품목유형별 재고 통계 조회", + "description": "품목유형별 재고 현황 통계를 조회합니다.", + "operationId": "1dd668e34fde9294f68a86475170eae8", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/StockStatsByItemType" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/stocks/{id}": { + "get": { + "tags": [ + "Stocks" + ], + "summary": "재고 상세 조회", + "description": "재고 상세 정보를 조회합니다. LOT 목록이 FIFO 순서로 포함됩니다.", + "operationId": "291fbfd65d45c53cc84ff16ef10f9096", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "재고 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/StockWithLots" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "재고 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions": { + "get": { + "tags": [ + "Subscriptions" + ], + "summary": "구독 목록 조회", + "description": "테넌트의 구독 목록을 조회합니다.", + "operationId": "38d64fe132a8788d729fdd754b7c5a23", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "pending", + "active", + "cancelled", + "expired", + "suspended" + ] + } + }, + { + "name": "valid_only", + "in": "query", + "description": "유효한 구독만", + "schema": { + "type": "boolean" + } + }, + { + "name": "expiring_within", + "in": "query", + "description": "N일 이내 만료 예정", + "schema": { + "type": "integer", + "maximum": 365, + "minimum": 1 + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일 (시작일 기준)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일 (시작일 기준)", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "started_at", + "enum": [ + "started_at", + "ended_at", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Subscription" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Subscriptions" + ], + "summary": "구독 등록", + "description": "새로운 구독을 등록합니다. 이미 활성 구독이 있으면 등록할 수 없습니다.", + "operationId": "8813133967ce592d700439e9914f4fcf", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Subscription" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "이미 활성 구독 존재", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "요금제 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/current": { + "get": { + "tags": [ + "Subscriptions" + ], + "summary": "현재 활성 구독 조회", + "description": "테넌트의 현재 활성 구독을 조회합니다.", + "operationId": "9962dea3f6ebabdd350147e6a25b5090", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/Subscription" + } + ], + "nullable": true + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/{id}": { + "get": { + "tags": [ + "Subscriptions" + ], + "summary": "구독 상세 조회", + "description": "구독 상세 정보를 조회합니다.", + "operationId": "140084710ccd62a0cb22a08aac1e7878", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "구독 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Subscription" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "구독 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/{id}/cancel": { + "post": { + "tags": [ + "Subscriptions" + ], + "summary": "구독 취소", + "description": "구독을 취소합니다. 활성(active) 또는 대기(pending) 상태에서만 가능합니다.", + "operationId": "c1e087b39e23be92c6930ef4300c11dd", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "구독 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequest" + } + } + } + }, + "responses": { + "200": { + "description": "취소 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Subscription" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "취소 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "구독 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/{id}/renew": { + "post": { + "tags": [ + "Subscriptions" + ], + "summary": "구독 갱신", + "description": "구독을 갱신합니다. 활성(active) 상태에서만 가능합니다.", + "operationId": "c8dfca231c46a72ed5e80933d8701445", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "구독 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "payment_method": { + "type": "string", + "enum": [ + "card", + "bank", + "virtual", + "cash", + "free" + ], + "example": "card" + }, + "transaction_id": { + "type": "string", + "example": "TXN654321" + }, + "auto_complete": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "갱신 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Subscription" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "갱신 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "구독 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/{id}/suspend": { + "post": { + "tags": [ + "Subscriptions" + ], + "summary": "구독 일시정지", + "description": "구독을 일시정지합니다. 활성(active) 상태에서만 가능합니다.", + "operationId": "c564addd49e815fd5cbb13f2b5a25cde", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "구독 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "일시정지 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Subscription" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "일시정지 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "구독 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/{id}/resume": { + "post": { + "tags": [ + "Subscriptions" + ], + "summary": "구독 재개", + "description": "일시정지된 구독을 재개합니다. 일시정지(suspended) 상태에서만 가능합니다.", + "operationId": "f96f9e35e08fa59c63a0de54d0138f99", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "구독 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "재개 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Subscription" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "재개 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "구독 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/usage": { + "get": { + "tags": [ + "Subscriptions" + ], + "summary": "사용량 조회", + "description": "테넌트의 사용자, 저장소, 구독 사용량 정보를 조회합니다.", + "operationId": "75677406ba261e23ca752d9bb7d7681a", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/UsageResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/export": { + "post": { + "tags": [ + "Subscriptions" + ], + "summary": "데이터 내보내기 요청", + "description": "테넌트 데이터를 내보내기 요청합니다. 백그라운드에서 처리되며 완료 후 다운로드 가능합니다.", + "operationId": "21f33fce83801f1ae4819f11544f6a3c", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExportCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "요청 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/DataExport" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "진행 중인 내보내기 존재", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "유효성 검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/subscriptions/export/{id}": { + "get": { + "tags": [ + "Subscriptions" + ], + "summary": "내보내기 상태 조회", + "description": "내보내기 요청의 현재 상태를 조회합니다.", + "operationId": "171cfe1ef5b4c516e8e0c778ccdf210a", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "내보내기 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/DataExport" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "내보내기 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/system-boards": { + "get": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 목록 조회", + "description": "본사에서 생성한 시스템 게시판 목록을 조회합니다.", + "operationId": "bd7c99ec4dd0b4566bac5b28f2645ec8", + "parameters": [ + { + "name": "board_type", + "in": "query", + "description": "게시판 유형 필터", + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "게시판명 검색", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Board" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/system-boards/{code}": { + "get": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 상세 조회", + "description": "시스템 게시판 코드로 상세 정보를 조회합니다.", + "operationId": "dc69e204791e2b9d43da7598f9392ac6", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "시스템 게시판 코드", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Board" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/system-boards/{code}/fields": { + "get": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 커스텀 필드 목록", + "operationId": "7773b7cc9015457141bc385c337dfbb7", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "시스템 게시판 코드", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BoardField" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/system-boards/{code}/posts": { + "get": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 목록 조회", + "operationId": "e8f6758601422b592002449ef533c9a1", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "시스템 게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "search", + "in": "query", + "description": "제목/내용 검색", + "schema": { + "type": "string" + } + }, + { + "name": "is_notice", + "in": "query", + "description": "공지사항 필터", + "schema": { + "type": "boolean" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string" + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 개수", + "schema": { + "type": "integer", + "default": 15 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/PostPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 작성", + "operationId": "79f9fa4f240fd0a05f91fee1be689941", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "시스템 게시판 코드", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "작성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Post" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "게시판 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/system-boards/{code}/posts/{id}": { + "get": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 상세 조회", + "operationId": "8cf83b21a44c7f605b55e4abeb7068c3", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "시스템 게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "게시글 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Post" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 수정", + "operationId": "045790df62e0a8e54c3633f721312667", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "시스템 게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "게시글 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Post" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "게시글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 삭제", + "operationId": "aed1913cf3f110beeb2c7d794237e7b5", + "parameters": [ + { + "name": "code", + "in": "path", + "description": "시스템 게시판 코드", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "게시글 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "게시글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/system-boards/{code}/posts/{postId}/comments": { + "get": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 댓글 목록", + "operationId": "3de02f98a9fe423261dba9f80a0511ca", + "parameters": [ + { + "name": "code", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Comment" + } + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 댓글 작성", + "operationId": "b525eac68c1caf7632d95b64e245de1e", + "parameters": [ + { + "name": "code", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "작성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Comment" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/system-boards/{code}/posts/{postId}/comments/{commentId}": { + "put": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 댓글 수정", + "operationId": "338f772ad8a9f1a1cec6c222bc739d83", + "parameters": [ + { + "name": "code", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "commentId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Comment" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "댓글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "SystemBoard" + ], + "summary": "시스템 게시판 게시글 댓글 삭제", + "operationId": "8aec04d4971e325a82135634eaec46ee", + "parameters": [ + { + "name": "code", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "postId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "commentId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "댓글 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tax-invoices": { + "get": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 목록 조회", + "description": "세금계산서 목록을 조회합니다. 다양한 필터 조건으로 검색할 수 있습니다.", + "operationId": "d98a1a2aab049b27f655800076e938d0", + "parameters": [ + { + "name": "direction", + "in": "query", + "description": "방향 (매출/매입)", + "schema": { + "type": "string", + "enum": [ + "sales", + "purchases" + ] + } + }, + { + "name": "status", + "in": "query", + "description": "상태", + "schema": { + "type": "string", + "enum": [ + "draft", + "issued", + "sent", + "cancelled", + "failed" + ] + } + }, + { + "name": "invoice_type", + "in": "query", + "description": "세금계산서 유형", + "schema": { + "type": "string", + "enum": [ + "tax_invoice", + "invoice", + "modified" + ] + } + }, + { + "name": "issue_type", + "in": "query", + "description": "발행 유형", + "schema": { + "type": "string", + "enum": [ + "normal", + "reverse", + "trustee" + ] + } + }, + { + "name": "issue_date_from", + "in": "query", + "description": "작성일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "issue_date_to", + "in": "query", + "description": "작성일 종료", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "corp_num", + "in": "query", + "description": "거래처 사업자번호 (공급자 또는 공급받는자)", + "schema": { + "type": "string" + } + }, + { + "name": "corp_name", + "in": "query", + "description": "거래처명 검색 (공급자 또는 공급받는자)", + "schema": { + "type": "string", + "maxLength": 100 + } + }, + { + "name": "nts_confirm_num", + "in": "query", + "description": "국세청 승인번호 검색", + "schema": { + "type": "string" + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TaxInvoice" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 100 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 생성", + "description": "새로운 세금계산서를 생성합니다. 생성 시 임시저장(draft) 상태로 저장됩니다.", + "operationId": "59542b824ad2e84873b472ca3bf01495", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaxInvoiceCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TaxInvoice" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tax-invoices/summary": { + "get": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 요약 통계", + "description": "세금계산서 요약 통계를 조회합니다. 방향별(매출/매입), 상태별 집계 정보를 제공합니다.", + "operationId": "cb10a375afac5a575a97dbea7a1c01b1", + "parameters": [ + { + "name": "issue_date_from", + "in": "query", + "description": "작성일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "issue_date_to", + "in": "query", + "description": "작성일 종료", + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TaxInvoiceSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tax-invoices/{id}": { + "get": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 상세 조회", + "description": "세금계산서 상세 정보를 조회합니다.", + "operationId": "46a50fa93e8f85d984f95d5837effa12", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "세금계산서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TaxInvoice" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "세금계산서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 수정", + "description": "세금계산서 정보를 수정합니다. 임시저장(draft) 상태에서만 수정 가능합니다.", + "operationId": "70a01c29f90aae4fbbb1f5f397c94d37", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "세금계산서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaxInvoiceUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TaxInvoice" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청 또는 수정 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "세금계산서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 삭제", + "description": "세금계산서를 삭제합니다. 임시저장(draft) 상태에서만 삭제 가능합니다. (Soft Delete)", + "operationId": "cb5d43fa8fe7d333d2b4b8f5535b4eda", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "세금계산서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "삭제 불가 상태", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "세금계산서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tax-invoices/{id}/issue": { + "post": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 발행", + "description": "세금계산서를 발행합니다. 바로빌 API를 통해 전자세금계산서가 발행됩니다. 임시저장(draft) 상태에서만 발행 가능합니다.", + "operationId": "8d31d4680c6f7603d12dbdf4591de8d3", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "세금계산서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "발행 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TaxInvoice" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "발행 불가 상태 또는 바로빌 설정 미완료", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "세금계산서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러 또는 바로빌 발행 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tax-invoices/{id}/cancel": { + "post": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 취소", + "description": "세금계산서를 취소합니다. 바로빌 API를 통해 전자세금계산서가 취소됩니다. 발행완료(issued) 또는 국세청 전송(sent) 상태에서만 취소 가능합니다.", + "operationId": "7f827334bd612921981faa0452588f15", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "세금계산서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaxInvoiceCancelRequest" + } + } + } + }, + "responses": { + "200": { + "description": "취소 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TaxInvoice" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "취소 불가 상태 또는 바로빌 취소 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "세금계산서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tax-invoices/{id}/check-status": { + "get": { + "tags": [ + "TaxInvoices" + ], + "summary": "국세청 전송 상태 조회", + "description": "세금계산서의 국세청 전송 상태를 조회합니다. 바로빌 API를 통해 최신 상태를 확인하고 업데이트합니다.", + "operationId": "70a4ea473a906611d19b5b3a5322fdc7", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "세금계산서 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TaxInvoice" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "세금계산서 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tax-invoices/bulk-issue": { + "post": { + "tags": [ + "TaxInvoices" + ], + "summary": "세금계산서 일괄 발행", + "description": "여러 세금계산서를 일괄 발행합니다. 바로빌 API를 통해 전자세금계산서가 발행됩니다. 임시저장(draft) 상태인 건만 발행되며, 각 건별로 성공/실패가 처리됩니다.", + "operationId": "af2427398cbc09d8a77e140eca997e94", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaxInvoiceBulkIssueRequest" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 발행 처리 완료", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TaxInvoiceBulkIssueResponse" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenants/list": { + "get": { + "tags": [ + "Tenant" + ], + "summary": "테넌트 목록 조회", + "description": "등록된 모든 테넌트 목록을 페이징 형태로 반환합니다.", + "operationId": "1da7f46bb2cc83f9ab4421da2e9e6838", + "parameters": [ + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "테넌트 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/TenantPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenants": { + "get": { + "tags": [ + "Tenant" + ], + "summary": "테넌트 정보 조회", + "description": "활성(현재) 테넌트의 상세 정보를 조회합니다. 필요 시 쿼리로 특정 테넌트를 확장할 수 있습니다.", + "operationId": "14929529f88cd0cc131becc668d844fe", + "parameters": [ + { + "name": "tenant_id", + "in": "query", + "description": "조회할 테넌트 ID (없으면 활성 테넌트)", + "required": false, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "테넌트 정보 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Tenant" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Tenant" + ], + "summary": "테넌트 정보 수정", + "description": "기존 테넌트 정보를 수정합니다.", + "operationId": "c5560747dd16ee297ef5ffefb11b0206", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "수정 성공" + }, + "data": { + "$ref": "#/components/schemas/TenantBrief" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Tenant" + ], + "summary": "테넌트 등록", + "description": "새로운 테넌트를 등록합니다.", + "operationId": "885d630533eb8264b2ccee3f2df39dfb", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "등록 성공" + }, + "data": { + "$ref": "#/components/schemas/TenantBrief" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Tenant" + ], + "summary": "테넌트 삭제(탈퇴)", + "description": "테넌트를 삭제(또는 탈퇴 처리)합니다.", + "operationId": "a1a8108fd51b14f6de2e5e8a86f212b8", + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "삭제 성공" + }, + "data": { + "type": "object", + "example": null, + "nullable": true + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenants/restore/{tenant_id}": { + "put": { + "tags": [ + "Tenant" + ], + "summary": "테넌트 복구", + "description": "삭제(소프트 삭제)된 테넌트를 복구합니다.", + "operationId": "d2ac0484bf09348f3634cf7f689dca39", + "parameters": [ + { + "name": "tenant_id", + "in": "path", + "description": "복구할 테넌트 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "복구 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "message": { + "type": "string", + "example": "복구 성공" + }, + "data": { + "type": "object", + "example": null, + "nullable": true + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/fields": { + "get": { + "tags": [ + "Settings - Fields" + ], + "summary": "테넌트 필드 설정 목록 조회", + "description": "전역 + 테넌트별 병합된 필드 설정 효과값을 조회합니다.", + "operationId": "584478dfdc703939920ef6bbc662f15b", + "responses": { + "200": { + "description": "필드 설정 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회 성공" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TenantFieldSetting" + } + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/fields/bulk": { + "put": { + "tags": [ + "Settings - Fields" + ], + "summary": "테넌트 필드 설정 대량 저장", + "description": "여러 필드 설정을 트랜잭션으로 일괄 저장합니다.", + "operationId": "32dd786160f266d37454acdcb31ec9f3", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantFieldSettingBulkRequest" + } + } + } + }, + "responses": { + "200": { + "description": "대량 저장 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "유효하지 않은 필드 타입", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "유효하지 않은 필드 타입입니다." + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검사 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/fields/{key}": { + "patch": { + "tags": [ + "Settings - Fields" + ], + "summary": "테넌트 필드 설정 단건 수정", + "description": "특정 필드 설정을 개별적으로 수정합니다.", + "operationId": "554546333a72736944f0181c23ef237c", + "parameters": [ + { + "name": "key", + "in": "path", + "description": "필드 키", + "required": true, + "schema": { + "type": "string", + "example": "product_name_required" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "field_value": { + "type": "string", + "example": "false" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "필드 설정 수정 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "필드 설정을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "해당 필드 설정을 찾을 수 없습니다." + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "유효하지 않은 필드 타입", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "유효하지 않은 필드 타입입니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenant-settings": { + "get": { + "tags": [ + "TenantSettings" + ], + "summary": "테넌트 설정 목록 조회", + "description": "현재 테넌트의 모든 설정을 그룹별로 조회합니다.", + "operationId": "252dca947e8c5ef245029ae045f11b7b", + "parameters": [ + { + "name": "group", + "in": "query", + "description": "특정 그룹만 조회", + "required": false, + "schema": { + "type": "string", + "example": "stock" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "properties": { + "stock": { + "properties": { + "stock_item_types": { + "properties": { + "value": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "TenantSettings" + ], + "summary": "설정 저장/업데이트", + "description": "설정을 저장하거나 업데이트합니다. 이미 존재하는 경우 업데이트됩니다.", + "operationId": "6686e8bf4aba700b3fd49657a9915ccc", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantSettingStoreRequest" + } + } + } + }, + "responses": { + "200": { + "description": "저장 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "수정되었습니다." + }, + "data": { + "$ref": "#/components/schemas/TenantSetting" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenant-settings/{group}/{key}": { + "get": { + "tags": [ + "TenantSettings" + ], + "summary": "단일 설정 조회", + "description": "그룹과 키로 특정 설정값을 조회합니다.", + "operationId": "69a4c4757b86a350d4f9a3eb8d34dbc4", + "parameters": [ + { + "name": "group", + "in": "path", + "description": "설정 그룹", + "required": true, + "schema": { + "type": "string", + "example": "stock" + } + }, + { + "name": "key", + "in": "path", + "description": "설정 키", + "required": true, + "schema": { + "type": "string", + "example": "stock_item_types" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "properties": { + "group": { + "type": "string", + "example": "stock" + }, + "key": { + "type": "string", + "example": "stock_item_types" + }, + "value": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "RM", + "SM", + "CS", + "PT", + "SF" + ] + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "TenantSettings" + ], + "summary": "설정 삭제", + "description": "특정 설정을 삭제합니다.", + "operationId": "3d1558d19ec888d70d83b6217a548f42", + "parameters": [ + { + "name": "group", + "in": "path", + "description": "설정 그룹", + "required": true, + "schema": { + "type": "string", + "example": "stock" + } + }, + { + "name": "key", + "in": "path", + "description": "설정 키", + "required": true, + "schema": { + "type": "string", + "example": "stock_item_types" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "삭제되었습니다." + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "설정을 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "해당 데이터를 찾을 수 없습니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenant-settings/bulk": { + "put": { + "tags": [ + "TenantSettings" + ], + "summary": "설정 일괄 저장", + "description": "같은 그룹의 여러 설정을 일괄 저장합니다.", + "operationId": "3063b4f3690c9aa3904392a7f5524eab", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantSettingBulkRequest" + } + } + } + }, + "responses": { + "200": { + "description": "일괄 저장 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "일괄 저장되었습니다." + }, + "data": { + "properties": { + "updated": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenant-settings/initialize": { + "post": { + "tags": [ + "TenantSettings" + ], + "summary": "기본 설정 초기화", + "description": "시스템 기본 설정값으로 초기화합니다. 이미 존재하는 설정은 건드리지 않습니다.", + "operationId": "0fecd9c97b6f1b0c03a874696c61ce7d", + "responses": { + "200": { + "description": "초기화 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "생성되었습니다." + }, + "data": { + "properties": { + "initialized": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenant-stat-fields": { + "get": { + "tags": [ + "TenantStatField" + ], + "summary": "통계 필드 목록 조회", + "operationId": "3b0f97a4b8570b72cbbfeb2f36095deb", + "parameters": [ + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "default": 20 + }, + "example": 20 + }, + { + "name": "target_table", + "in": "query", + "schema": { + "type": "string" + }, + "example": "products" + }, + { + "name": "is_critical", + "in": "query", + "schema": { + "type": "boolean" + }, + "example": true + }, + { + "name": "aggregation_type", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "avg", + "sum", + "min", + "max", + "count" + ] + }, + "example": "avg" + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "통계 필드를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/TenantStatFieldPagination" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "TenantStatField" + ], + "summary": "통계 필드 생성", + "operationId": "e4d26c117590e625184e2617d0a360ab", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantStatFieldCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "통계 필드가 생성되었습니다." + }, + "data": { + "$ref": "#/components/schemas/TenantStatField" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenant-stat-fields/{id}": { + "get": { + "tags": [ + "TenantStatField" + ], + "summary": "통계 필드 단건 조회", + "operationId": "029ad663de43792a9f6d7a4fe5a14db4", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "통계 필드를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/TenantStatField" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "TenantStatField" + ], + "summary": "통계 필드 삭제", + "operationId": "8a3fb8a793e4b57b61fba24174ff7b2b", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "통계 필드가 삭제되었습니다." + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "TenantStatField" + ], + "summary": "통계 필드 수정", + "operationId": "38f5701df6f813a3fb9ba2aa79fc37d1", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantStatFieldUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "통계 필드가 수정되었습니다." + }, + "data": { + "$ref": "#/components/schemas/TenantStatField" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenant-stat-fields/reorder": { + "post": { + "tags": [ + "TenantStatField" + ], + "summary": "통계 필드 정렬순서 변경", + "operationId": "076b4f61dd96a6ee67a2ba23173af185", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantStatFieldReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "통계 필드 정렬이 변경되었습니다." + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/tenant-stat-fields/bulk-upsert": { + "put": { + "tags": [ + "TenantStatField" + ], + "summary": "통계 필드 일괄 생성/수정", + "operationId": "b4a3d4925fe3faf064f6e08c7a183c5e", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TenantStatFieldBulkUpsertRequest" + } + } + } + }, + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "통계 필드가 일괄 저장되었습니다." + }, + "data": { + "properties": { + "created": { + "type": "integer", + "example": 3 + }, + "updated": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [], + "BearerAuth": [] + } + ] + } + }, + "/api/v1/today-issues/summary": { + "get": { + "tags": [ + "TodayIssue" + ], + "summary": "오늘의 이슈 리스트 조회", + "description": "CEO 대시보드용 오늘의 이슈 리스트를 조회합니다. 수주 성공, 미수금 이슈, 재고 이슈, 지출예상내역서, 세금 신고, 결재 요청, 기타 카테고리의 알림을 집계합니다.", + "operationId": "getTodayIssueSummary", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "조회할 최대 항목 수", + "required": false, + "schema": { + "type": "integer", + "default": 30, + "maximum": 100, + "minimum": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/TodayIssueSummaryResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "인증에 실패했습니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/today-issues/unread": { + "get": { + "tags": [ + "TodayIssue" + ], + "summary": "읽지 않은 이슈 목록 조회 (헤더 알림용)", + "description": "헤더 알림 드롭다운에 표시할 읽지 않은 이슈 목록을 조회합니다.", + "operationId": "getUnreadTodayIssues", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "조회할 최대 항목 수 (기본 10)", + "required": false, + "schema": { + "type": "integer", + "default": 10, + "maximum": 50, + "minimum": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/TodayIssueUnreadResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "인증에 실패했습니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/today-issues/unread/count": { + "get": { + "tags": [ + "TodayIssue" + ], + "summary": "읽지 않은 이슈 개수 조회 (헤더 뱃지용)", + "description": "헤더 알림 아이콘 뱃지에 표시할 읽지 않은 이슈 개수를 조회합니다.", + "operationId": "getUnreadTodayIssueCount", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/TodayIssueUnreadCountResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "인증에 실패했습니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/today-issues/{id}/read": { + "post": { + "tags": [ + "TodayIssue" + ], + "summary": "이슈 읽음 처리", + "description": "특정 이슈를 읽음 처리합니다. 헤더 알림에서 항목 클릭 시 호출됩니다.", + "operationId": "markTodayIssueAsRead", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "이슈 ID", + "required": true, + "schema": { + "type": "integer", + "example": 123 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "알림을 읽음 처리했습니다." + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "이슈를 찾을 수 없음", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "데이터를 찾을 수 없습니다." + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "인증에 실패했습니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/today-issues/read-all": { + "post": { + "tags": [ + "TodayIssue" + ], + "summary": "모든 이슈 읽음 처리", + "description": "읽지 않은 모든 이슈를 읽음 처리합니다. 헤더 알림에서 '모두 읽음' 버튼 클릭 시 호출됩니다.", + "operationId": "markAllTodayIssuesAsRead", + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "모든 알림을 읽음 처리했습니다." + }, + "data": { + "$ref": "#/components/schemas/TodayIssueMarkAllReadResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "인증에 실패했습니다." + } + }, + "type": "object" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/me": { + "get": { + "tags": [ + "User" + ], + "summary": "내 정보 조회", + "description": "내 정보와 활성 테넌트 정보를 반환합니다.", + "operationId": "25ef25873e2756fbdbb61949c897b075", + "responses": { + "200": { + "description": "나의 정보 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/MeResponseData" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패 (헤더 누락, 유효하지 않은 토큰/키 등)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "User" + ], + "summary": "내 정보 수정", + "description": "이름/연락처 등 프로필 정보를 수정합니다.", + "operationId": "a6a81728b6ecc681b3dae955f2383a7f", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Member" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/me/password": { + "put": { + "tags": [ + "User" + ], + "summary": "비밀번호 변경", + "description": "현재 비밀번호 검증 후 새 비밀번호로 변경합니다.", + "operationId": "47151ae2bca6fb8efb58332da5a6475f", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PasswordChangeRequest" + } + } + } + }, + "responses": { + "204": { + "description": "변경 성공(콘텐츠 없음)", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "변경 성공" + }, + "data": { + "type": "object", + "example": null, + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/me/tenants": { + "get": { + "tags": [ + "User" + ], + "summary": "내 테넌트 목록", + "description": "사용자가 소속된 테넌트 목록을 반환합니다.", + "operationId": "986c01610b0373b2c53c7aefd5e0df0b", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "properties": { + "tenant_id": { + "type": "integer", + "example": 1 + }, + "tenant_name": { + "type": "string", + "example": "경동기업" + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/me/tenants/switch": { + "patch": { + "tags": [ + "User" + ], + "summary": "활성 테넌트 전환", + "description": "현재 세션/토큰의 활성 테넌트를 전환합니다.", + "operationId": "b0225e29ba33d6093c6da5f2516925ae", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SwitchTenantRequest" + } + } + } + }, + "responses": { + "204": { + "description": "전환 성공(콘텐츠 없음)", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "변경 성공" + }, + "data": { + "type": "object", + "example": null, + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/index": { + "get": { + "tags": [ + "User" + ], + "summary": "회원 목록 조회", + "description": "회원 목록을 페이징 형태로 반환합니다.", + "operationId": "94b74f7bfac12fbd9f71ec3c84dcacf5", + "parameters": [ + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "회원 목록 조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/MemberPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "필수 파라미터 누락", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "존재하지 않는 URI 또는 데이터", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/show/{user_no}": { + "get": { + "tags": [ + "User" ], "summary": "회원 상세조회", "description": "user_no 기준으로 회원 상세 정보를 조회합니다.", - "operationId": "b4c822915531828ea5f3a50d5112ef26", + "operationId": "82ca760bf7feaede190b26e443bf716e", "parameters": [ { "name": "user_no", @@ -354,6 +55337,155 @@ "responses": { "200": { "description": "회원 상세조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Member" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "회원 정보 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "405": { + "description": "허용되지 않는 메서드", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/invitations": { + "get": { + "tags": [ + "UserInvitation" + ], + "summary": "초대 목록 조회", + "description": "테넌트의 사용자 초대 목록을 조회합니다.", + "operationId": "getUserInvitations", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "상태 필터", + "required": false, + "schema": { + "type": "string", + "enum": [ + "pending", + "accepted", + "expired", + "cancelled" + ] + } + }, + { + "name": "search", + "in": "query", + "description": "이메일 검색", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "required": false, + "schema": { + "type": "string", + "default": "created_at", + "enum": [ + "created_at", + "expires_at", + "email" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "required": false, + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "required": false, + "schema": { + "type": "integer", + "default": 20, + "maximum": 100, + "minimum": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", "content": { "application/json": { "schema": { @@ -364,72 +55496,150 @@ }, "message": { "type": "string", - "example": "회원 상세조회 성공" + "example": "조회 완료" + }, + "data": { + "$ref": "#/components/schemas/UserInvitationPagination" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/invite": { + "post": { + "tags": [ + "UserInvitation" + ], + "summary": "사용자 초대", + "description": "새로운 사용자를 테넌트에 초대합니다. 초대 이메일이 발송됩니다.", + "operationId": "inviteUser", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InviteUserRequest" + } + } + } + }, + "responses": { + "200": { + "description": "초대 발송 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "초대가 발송되었습니다" + }, + "data": { + "$ref": "#/components/schemas/UserInvitation" + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "이미 가입된 사용자 또는 대기 중인 초대 존재" + }, + "401": { + "description": "인증 실패" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/invitations/{token}/accept": { + "post": { + "tags": [ + "UserInvitation" + ], + "summary": "초대 수락", + "description": "초대를 수락하고 사용자 계정을 생성합니다. 인증 불필요.", + "operationId": "acceptInvitation", + "parameters": [ + { + "name": "token", + "in": "path", + "description": "초대 토큰", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcceptInvitationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "초대 수락 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "초대가 수락되었습니다" }, "data": { "properties": { "id": { - "type": "integer", - "example": 1 - }, - "user_id": { - "type": "string", - "example": "hamss" - }, - "phone": { - "type": "string", - "example": "010-4820-9104" - }, - "options": { - "type": "string", - "example": null, - "nullable": true + "type": "integer" }, "name": { - "type": "string", - "example": "권혁성" + "type": "string" }, "email": { - "type": "string", - "example": "shine1324@gmail.com" - }, - "email_verified_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true - }, - "last_login_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true - }, - "current_team_id": { - "type": "integer", - "example": null, - "nullable": true - }, - "profile_photo_path": { - "type": "string", - "example": null, - "nullable": true - }, - "created_at": { - "type": "string", - "format": "date-time", - "example": "2025-07-16 18:28:41" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "example": "2025-07-25 23:13:06" - }, - "deleted_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true + "type": "string" } }, "type": "object" @@ -440,11 +55650,75 @@ } } }, + "400": { + "description": "만료된 초대 또는 잘못된 상태" + }, + "404": { + "description": "초대를 찾을 수 없음" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/api/v1/users/invitations/{id}": { + "delete": { + "tags": [ + "UserInvitation" + ], + "summary": "초대 취소", + "description": "대기 중인 초대를 취소합니다.", + "operationId": "cancelInvitation", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "초대 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "취소 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "초대가 취소되었습니다" + }, + "data": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + } + }, + "400": { + "description": "취소할 수 없는 상태" + }, "401": { "description": "인증 실패" }, "404": { - "description": "회원 정보 없음" + "description": "초대를 찾을 수 없음" } }, "security": [ @@ -457,17 +55731,28 @@ ] } }, - "/api/v1/member/me": { - "get": { + "/api/v1/users/invitations/{id}/resend": { + "post": { "tags": [ - "Member" + "UserInvitation" + ], + "summary": "초대 재발송", + "description": "대기 중인 초대 이메일을 재발송합니다. 만료 기간이 연장됩니다.", + "operationId": "resendInvitation", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "초대 ID", + "required": true, + "schema": { + "type": "integer" + } + } ], - "summary": "내 정보 조회", - "description": "내정보와 테넌트 정보를 전달 합니다.", - "operationId": "0c641be8a4e4ab5e1c2db29989b219ce", "responses": { "200": { - "description": "나의 정보 조회 성공", + "description": "재발송 성공", "content": { "application/json": { "schema": { @@ -478,147 +55763,10 @@ }, "message": { "type": "string", - "example": "나의 정보 조회 성공" + "example": "초대가 재발송되었습니다" }, "data": { - "properties": { - "user": { - "properties": { - "id": { - "type": "integer", - "example": 3 - }, - "user_id": { - "type": "string", - "example": "test" - }, - "phone": { - "type": "string", - "example": "010-1234-5678" - }, - "options": { - "type": "string", - "example": null, - "nullable": true - }, - "name": { - "type": "string", - "example": "테스트" - }, - "email": { - "type": "string", - "example": "test@5130.co.kr" - }, - "email_verified_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true - }, - "last_login_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true - }, - "current_team_id": { - "type": "integer", - "example": null, - "nullable": true - }, - "profile_photo_path": { - "type": "string", - "example": null, - "nullable": true - }, - "created_at": { - "type": "string", - "format": "date-time", - "example": "2025-07-17 13:19:37" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "example": "2025-07-26 15:51:14" - }, - "deleted_at": { - "type": "string", - "format": "date-time", - "example": null, - "nullable": true - } - }, - "type": "object" - }, - "tenant": { - "properties": { - "id": { - "type": "integer", - "example": 1 - }, - "company_name": { - "type": "string", - "example": "(주)경동기업" - }, - "code": { - "type": "string", - "example": "KDCOM" - }, - "email": { - "type": "string", - "example": "kd5130@naver.com" - }, - "phone": { - "type": "string", - "example": "01083935130" - }, - "address": { - "type": "string", - "example": "경기도 김포시 통진읍 옹정로 45-22" - }, - "business_num": { - "type": "string", - "example": "1398700333" - }, - "corp_reg_no": { - "type": "string", - "example": null, - "nullable": true - }, - "ceo_name": { - "type": "string", - "example": "이경호" - }, - "homepage": { - "type": "string", - "example": null, - "nullable": true - }, - "fax": { - "type": "string", - "example": null, - "nullable": true - }, - "logo": { - "type": "string", - "example": null, - "nullable": true - }, - "admin_memo": { - "type": "string", - "example": null, - "nullable": true - }, - "options": { - "type": "string", - "example": null, - "nullable": true - } - }, - "type": "object" - } - }, - "type": "object" + "$ref": "#/components/schemas/UserInvitation" } }, "type": "object" @@ -626,8 +55774,14 @@ } } }, + "400": { + "description": "재발송할 수 없는 상태" + }, "401": { - "description": "인증 실패 (헤더 누락, 유효하지 않은 토큰/키 등)" + "description": "인증 실패" + }, + "404": { + "description": "초대를 찾을 수 없음" } }, "security": [ @@ -640,82 +55794,465 @@ ] } }, - "/api/v1/product/category": { + "/api/v1/users/{id}/roles": { "get": { "tags": [ - "Product" + "UserRole" + ], + "summary": "사용자의 역할 목록 조회", + "description": "해당 사용자에게 현재 부여된 역할 목록을 반환합니다.", + "operationId": "c632d96413baf2736a38e0e35fd80e28", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } ], - "summary": "제품 카테고리 목록 조회", - "description": "제품 카테고리(최상위, parent_id=null) 리스트를 반환합니다.", - "operationId": "ae018aa8eec41762f28513ae1aecebfc", "responses": { "200": { - "description": "카테고리 목록 조회 성공", + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoleBrief" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "사용자 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "UserRole" + ], + "summary": "사용자에게 역할 부여", + "description": "role_names 또는 role_ids로 여러 역할을 부여합니다.", + "operationId": "5862e4057633642f52e0a664b20c17a5", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserRoleGrantRequest" + } + } + } + }, + "responses": { + "200": { + "description": "부여 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "사용자/역할 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "UserRole" + ], + "summary": "사용자의 역할 회수", + "description": "role_names 또는 role_ids로 여러 역할을 회수합니다.", + "operationId": "1b76cb9bd4edfce12039c39cbe111050", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserRoleRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "회수 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "사용자/역할 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/users/{id}/roles/sync": { + "put": { + "tags": [ + "UserRole" + ], + "summary": "사용자의 역할 동기화(교체)", + "description": "전달된 목록으로 사용자의 역할을 완전히 교체합니다.", + "operationId": "4d63bceda2b2693f83a0f465ce648f32", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + }, + "example": 1 + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserRoleSyncRequest" + } + } + } + }, + "responses": { + "200": { + "description": "동기화 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "404": { + "description": "사용자/역할 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "422": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "권한 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/vat/summary": { + "get": { + "tags": [ + "Vat" + ], + "summary": "부가세 현황 요약 조회", + "description": "CEO 대시보드용 부가세 현황 요약 데이터를 조회합니다. 매출세액, 매입세액, 예상 납부세액, 미발행 세금계산서 건수를 포함합니다.", + "operationId": "getVatSummary", + "parameters": [ + { + "name": "period_type", + "in": "query", + "description": "기간 타입 (quarter: 분기, half: 반기, year: 연간)", + "required": false, + "schema": { + "type": "string", + "default": "quarter", + "enum": [ + "quarter", + "half", + "year" + ] + } + }, + { + "name": "year", + "in": "query", + "description": "연도 (기본: 현재 연도)", + "required": false, + "schema": { + "type": "integer", + "example": 2026 + } + }, + { + "name": "period", + "in": "query", + "description": "기간 번호 (quarter: 1-4, half: 1-2, 기본: 현재 기간)", + "required": false, + "schema": { + "type": "integer", + "maximum": 4, + "minimum": 1, + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", "content": { "application/json": { "schema": { "properties": { - "status": { - "type": "string", - "example": "success" + "success": { + "type": "boolean", + "example": true }, "message": { "type": "string", - "example": "get 성공" + "example": "조회되었습니다." }, "data": { - "type": "array", - "items": { - "properties": { - "id": { - "type": "integer", - "example": 4 - }, - "code_group": { - "type": "string", - "example": "category" - }, - "code": { - "type": "string", - "example": "BP" - }, - "name": { - "type": "string", - "example": "절곡판" - }, - "parent_id": { - "type": "integer", - "example": null - }, - "attributes": { - "type": "string", - "example": "[{...}]" - }, - "description": { - "type": "string", - "example": "절곡판" - }, - "is_active": { - "type": "integer", - "example": 1 - }, - "sort_order": { - "type": "integer", - "example": 10 - }, - "created_at": { - "type": "string", - "format": "date-time", - "example": "2025-07-23T09:00:00Z" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "example": "2025-07-23T09:00:00Z" - } - }, - "type": "object" - } + "$ref": "#/components/schemas/VatSummaryResponse" } }, "type": "object" @@ -726,8 +56263,2946 @@ "401": { "description": "인증 실패" }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/vendor-ledger": { + "get": { + "tags": [ + "VendorLedger" + ], + "summary": "거래처원장 목록 조회", + "description": "거래처별 매출/수금 집계 목록을 조회합니다.", + "operationId": "getVendorLedgerList", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "거래처명 검색", + "schema": { + "type": "string", + "example": "ABC" + } + }, + { + "name": "start_date", + "in": "query", + "description": "조회 시작일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "조회 종료일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준 (name)", + "schema": { + "type": "string", + "default": "name" + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "asc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "name": "per_page", + "in": "query", + "description": "페이지당 항목 수", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "page", + "in": "query", + "description": "페이지 번호", + "schema": { + "type": "integer", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/VendorLedgerPagination" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/vendor-ledger/summary": { + "get": { + "tags": [ + "VendorLedger" + ], + "summary": "거래처원장 요약 통계", + "description": "전체 거래처의 매출/수금 요약 통계를 조회합니다.", + "operationId": "getVendorLedgerSummary", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "조회 시작일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "조회 종료일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/VendorLedgerSummary" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/vendor-ledger/{clientId}": { + "get": { + "tags": [ + "VendorLedger" + ], + "summary": "거래처원장 상세 조회", + "description": "특정 거래처의 상세 거래 내역을 조회합니다.", + "operationId": "getVendorLedgerDetail", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "거래처 ID", + "required": true, + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "start_date", + "in": "query", + "description": "조회 시작일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-01-01" + } + }, + { + "name": "end_date", + "in": "query", + "description": "조회 종료일", + "schema": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "데이터를 조회했습니다." + }, + "data": { + "$ref": "#/components/schemas/VendorLedgerDetail" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + }, + "404": { + "description": "거래처를 찾을 수 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/welfare/summary": { + "get": { + "tags": [ + "Welfare" + ], + "summary": "복리후생비 현황 요약 조회", + "description": "CEO 대시보드용 복리후생비 현황 요약 데이터를 조회합니다. 연간/분기별 한도, 사용금액, 잔여한도를 포함합니다.", + "operationId": "getWelfareSummary", + "parameters": [ + { + "name": "limit_type", + "in": "query", + "description": "기간 타입 (annual: 연간, quarterly: 분기)", + "required": false, + "schema": { + "type": "string", + "default": "quarterly", + "enum": [ + "annual", + "quarterly" + ] + } + }, + { + "name": "calculation_type", + "in": "query", + "description": "계산 방식 (fixed: 1인당 정액, ratio: 급여 대비 비율)", + "required": false, + "schema": { + "type": "string", + "default": "fixed", + "enum": [ + "fixed", + "ratio" + ] + } + }, + { + "name": "fixed_amount_per_month", + "in": "query", + "description": "1인당 월 정액 (calculation_type=fixed일 때 사용, 기본: 200000)", + "required": false, + "schema": { + "type": "integer", + "example": 200000 + } + }, + { + "name": "ratio", + "in": "query", + "description": "급여 대비 비율 (calculation_type=ratio일 때 사용, 기본: 0.05)", + "required": false, + "schema": { + "type": "number", + "format": "float", + "example": 0.05 + } + }, + { + "name": "year", + "in": "query", + "description": "연도 (기본: 현재 연도)", + "required": false, + "schema": { + "type": "integer", + "example": 2026 + } + }, + { + "name": "quarter", + "in": "query", + "description": "분기 번호 (1-4, 기본: 현재 분기)", + "required": false, + "schema": { + "type": "integer", + "maximum": 4, + "minimum": 1, + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "$ref": "#/components/schemas/WelfareSummaryResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/welfare/detail": { + "get": { + "tags": [ + "Welfare" + ], + "summary": "복리후생비 상세 조회 (모달용)", + "description": "CEO 대시보드 복리후생비 모달용 상세 데이터를 조회합니다. 요약 카드, 월별 추이, 항목별 분포, 사용 내역, 분기별 현황을 포함합니다.", + "operationId": "getWelfareDetail", + "parameters": [ + { + "name": "calculation_type", + "in": "query", + "description": "계산 방식 (fixed: 1인당 정액, ratio: 급여 대비 비율)", + "required": false, + "schema": { + "type": "string", + "default": "fixed", + "enum": [ + "fixed", + "ratio" + ] + } + }, + { + "name": "fixed_amount_per_month", + "in": "query", + "description": "1인당 월 정액 (calculation_type=fixed일 때 사용, 기본: 200000)", + "required": false, + "schema": { + "type": "integer", + "example": 200000 + } + }, + { + "name": "ratio", + "in": "query", + "description": "급여 대비 비율 (calculation_type=ratio일 때 사용, 기본: 0.05)", + "required": false, + "schema": { + "type": "number", + "format": "float", + "example": 0.05 + } + }, + { + "name": "year", + "in": "query", + "description": "연도 (기본: 현재 연도)", + "required": false, + "schema": { + "type": "integer", + "example": 2026 + } + }, + { + "name": "quarter", + "in": "query", + "description": "분기 번호 (1-4, 기본: 현재 분기)", + "required": false, + "schema": { + "type": "integer", + "maximum": 4, + "minimum": 1, + "example": 1 + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "조회되었습니다." + }, + "data": { + "$ref": "#/components/schemas/WelfareDetailResponse" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + }, + "403": { + "description": "권한 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/withdrawals": { + "get": { + "tags": [ + "Withdrawals" + ], + "summary": "출금 목록 조회", + "description": "출금 목록을 조회합니다.", + "operationId": "6d10a744c6f689b6b56dd59d4c9dd6ed", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "검색어 (거래처명, 적요)", + "schema": { + "type": "string" + } + }, + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "payment_method", + "in": "query", + "description": "결제수단", + "schema": { + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ] + } + }, + { + "name": "bank_account_id", + "in": "query", + "description": "계좌 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "sort_by", + "in": "query", + "description": "정렬 기준", + "schema": { + "type": "string", + "default": "withdrawal_date", + "enum": [ + "withdrawal_date", + "amount", + "created_at" + ] + } + }, + { + "name": "sort_dir", + "in": "query", + "description": "정렬 방향", + "schema": { + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ] + } + }, + { + "$ref": "#/components/parameters/Page" + }, + { + "$ref": "#/components/parameters/Size" + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Withdrawal" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 30 + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, "500": { - "description": "서버 에러" + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Withdrawals" + ], + "summary": "출금 등록", + "description": "새로운 출금을 등록합니다.", + "operationId": "9960cabe8221ffa19afb98a13bdda054", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WithdrawalCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Withdrawal" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/withdrawals/summary": { + "get": { + "tags": [ + "Withdrawals" + ], + "summary": "출금 요약 조회", + "description": "기간별 출금 요약을 조회합니다.", + "operationId": "e0d8086dd19e0a3490f69c71472fb55a", + "parameters": [ + { + "name": "start_date", + "in": "query", + "description": "시작일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "end_date", + "in": "query", + "description": "종료일", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "client_id", + "in": "query", + "description": "거래처 ID", + "schema": { + "type": "integer" + } + }, + { + "name": "payment_method", + "in": "query", + "description": "결제수단", + "schema": { + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ] + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WithdrawalSummary" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/withdrawals/{id}": { + "get": { + "tags": [ + "Withdrawals" + ], + "summary": "출금 상세 조회", + "description": "출금 상세 정보를 조회합니다.", + "operationId": "2ceea8bd118c891938c53dbd920749b4", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "출금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Withdrawal" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "출금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "Withdrawals" + ], + "summary": "출금 수정", + "description": "출금 정보를 수정합니다.", + "operationId": "a75e277a5e031b12d40e13090c0c7249", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "출금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WithdrawalUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/Withdrawal" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "출금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Withdrawals" + ], + "summary": "출금 삭제", + "description": "출금을 삭제합니다. (Soft Delete)", + "operationId": "d8bb5c6ec6af37eaedcd4f815dd539a5", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "출금 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "출금 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders": { + "get": { + "tags": [ + "WorkOrder" + ], + "summary": "작업지시 목록", + "operationId": "ce4a056eaf9c697ca236e907a607646a", + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { + "type": "integer", + "example": 1 + } + }, + { + "name": "size", + "in": "query", + "schema": { + "type": "integer", + "example": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "작업지시번호/프로젝트명 검색", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "상태 필터", + "schema": { + "type": "string", + "enum": [ + "unassigned", + "pending", + "waiting", + "in_progress", + "completed", + "shipped" + ] + } + }, + { + "name": "process_type", + "in": "query", + "description": "공정유형 필터", + "schema": { + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ] + } + }, + { + "name": "assignee_id", + "in": "query", + "description": "담당자 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "team_id", + "in": "query", + "description": "팀 필터", + "schema": { + "type": "integer" + } + }, + { + "name": "scheduled_from", + "in": "query", + "description": "예정일 시작", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "scheduled_to", + "in": "query", + "description": "예정일 종료", + "schema": { + "type": "string", + "format": "date" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrderPagination" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "WorkOrder" + ], + "summary": "작업지시 생성", + "operationId": "8dddb97f61c88be4da82817d36292f59", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkOrderCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "생성 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrder" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "검증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/stats": { + "get": { + "tags": [ + "WorkOrder" + ], + "summary": "작업지시 통계", + "operationId": "73cd6bebdd0986bf3693054ccc003aa8", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrderStats" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/{id}": { + "get": { + "tags": [ + "WorkOrder" + ], + "summary": "작업지시 단건 조회", + "operationId": "cc230c06723c9149c22c57f5e205f90e", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrder" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "WorkOrder" + ], + "summary": "작업지시 수정", + "operationId": "7ffbef98aa26c96db570a464510d0b30", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkOrderUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrder" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "WorkOrder" + ], + "summary": "작업지시 삭제", + "description": "진행 중이거나 완료된 작업지시는 삭제할 수 없습니다.", + "operationId": "43ece42451d78087ac3b405e021a5dbb", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "삭제 불가", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/{id}/status": { + "patch": { + "tags": [ + "WorkOrder" + ], + "summary": "상태 변경", + "operationId": "5eea58bb9762615acf55eb4a48e6d792", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "type": "string", + "enum": [ + "unassigned", + "pending", + "waiting", + "in_progress", + "completed", + "shipped" + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "변경 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrder" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/{id}/assign": { + "patch": { + "tags": [ + "WorkOrder" + ], + "summary": "담당자 배정", + "operationId": "d4ee5957dd61d10fab5db6bded43a5a3", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "assignee_id": { + "description": "담당자 ID", + "type": "integer" + }, + "team_id": { + "description": "팀 ID", + "type": "integer", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "배정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrder" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/{id}/bending/toggle": { + "patch": { + "tags": [ + "WorkOrder" + ], + "summary": "벤딩 항목 토글", + "description": "벤딩 공정의 세부 항목 완료 여부를 토글합니다.", + "operationId": "a3c2a2030fa785695f8b27ffae7e56d0", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "field": { + "type": "string", + "enum": [ + "shaft_cutting", + "bearing", + "shaft_welding", + "assembly", + "winder_welding", + "frame_assembly", + "bundle_assembly", + "motor_assembly", + "bracket_assembly" + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "토글 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrderBendingDetail" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "벤딩 공정이 아님", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/{id}/issues": { + "post": { + "tags": [ + "WorkOrder" + ], + "summary": "이슈 추가", + "operationId": "3b1a7788195517c5470deebc3830f92f", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "title": { + "type": "string", + "maxLength": 200 + }, + "description": { + "type": "string", + "nullable": true + }, + "priority": { + "type": "string", + "enum": [ + "high", + "medium", + "low" + ], + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "추가 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrderIssue" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/{workOrderId}/issues/{issueId}/resolve": { + "patch": { + "tags": [ + "WorkOrder" + ], + "summary": "이슈 해결", + "operationId": "4bc295a7cde7f806065bb39bad94b164", + "parameters": [ + { + "name": "workOrderId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "issueId", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "해결 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkOrderIssue" + } + }, + "type": "object" + } + ] + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/{id}/materials": { + "get": { + "tags": [ + "WorkOrder" + ], + "summary": "자재 목록 조회", + "description": "작업지시에 필요한 자재 목록을 조회합니다. (BOM 기반)", + "operationId": "a7ad7a6697e93de31e0bdd01cfc228f4", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "작업지시 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "material_code": { + "type": "string", + "example": "MAT-100" + }, + "material_name": { + "type": "string", + "example": "방충망 프레임" + }, + "unit": { + "type": "string", + "example": "EA" + }, + "current_stock": { + "type": "integer", + "example": 100 + }, + "fifo_rank": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-orders/{id}/material-inputs": { + "post": { + "tags": [ + "WorkOrder" + ], + "summary": "자재 투입 등록", + "description": "작업지시에 자재 투입을 등록합니다.", + "operationId": "f78cff6ca4bf4540cf979d12a831be47", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "작업지시 ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "material_ids": { + "description": "투입할 자재 ID 목록", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "properties": { + "work_order_id": { + "type": "integer", + "example": 1 + }, + "material_count": { + "type": "integer", + "example": 3 + }, + "input_at": { + "type": "string", + "example": "2025-01-20 10:30:00" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + } + } + } + }, + "404": { + "description": "데이터 없음", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-results": { + "get": { + "tags": [ + "WorkResult" + ], + "summary": "작업실적 목록 조회", + "operationId": "253b9026197af9765b847a7a5b773677", + "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "q", + "in": "query", + "description": "검색어 (로트번호, 품목명, 작업지시번호)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "process_type", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ] + } + }, + { + "name": "work_order_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "worker_id", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "work_date_from", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "work_date_to", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "is_inspected", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "is_packaged", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/WorkResultPagination" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "WorkResult" + ], + "summary": "작업실적 등록", + "operationId": "14cab0e0ab2196b002e054c9657885f6", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkResultCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "등록 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/WorkResult" + } + }, + "type": "object" + } + } + } + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-results/stats": { + "get": { + "tags": [ + "WorkResult" + ], + "summary": "작업실적 통계 조회", + "operationId": "847f711d6deecbcad25b3fa5b4099338", + "parameters": [ + { + "name": "work_date_from", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "work_date_to", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "process_type", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ] + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/WorkResultStats" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "인증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-results/{id}": { + "get": { + "tags": [ + "WorkResult" + ], + "summary": "작업실적 상세 조회", + "operationId": "4831129592b32938993d2cfa10301a50", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/WorkResult" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "리소스 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "WorkResult" + ], + "summary": "작업실적 수정", + "operationId": "b57f3ae56cacd05c6742e1c208d3f864", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkResultUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/WorkResult" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "리소스 없음" + }, + "422": { + "description": "유효성 검증 실패" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "WorkResult" + ], + "summary": "작업실적 삭제", + "operationId": "249a7d1326222e24df7758bb5df03b5c", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "삭제 성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "type": "string", + "example": "success" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "리소스 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-results/{id}/inspection": { + "patch": { + "tags": [ + "WorkResult" + ], + "summary": "검사 상태 토글", + "operationId": "016d6dff87d087ac618279cd483a313b", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/WorkResult" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "리소스 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/work-results/{id}/packaging": { + "patch": { + "tags": [ + "WorkResult" + ], + "summary": "포장 상태 토글", + "operationId": "8fe24768fa4930cf60f8e7b8fe28a2bc", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "성공", + "content": { + "application/json": { + "schema": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/WorkResult" + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "리소스 없음" + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/work": { + "get": { + "tags": [ + "WorkSettings" + ], + "summary": "근무 설정 조회", + "description": "테넌트의 근무 설정을 조회합니다. 설정이 없으면 기본값으로 자동 생성됩니다.", + "operationId": "e5ded47dad2c8082b2f9cd6798039f15", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkSetting" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "WorkSettings" + ], + "summary": "근무 설정 수정", + "description": "테넌트의 근무 설정을 수정합니다.", + "operationId": "dbde24c3c34f1586b465156d9ea0bb7a", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkSettingUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/WorkSetting" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + } + }, + "/api/v1/settings/attendance": { + "get": { + "tags": [ + "WorkSettings" + ], + "summary": "출퇴근 설정 조회", + "description": "테넌트의 출퇴근 설정을 조회합니다. 설정이 없으면 기본값으로 자동 생성됩니다.", + "operationId": "4c7e67a50672bd5eb8d511182869ec42", + "responses": { + "200": { + "description": "조회 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/AttendanceSetting" + } + }, + "type": "object" + } + ] + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ] + }, + "put": { + "tags": [ + "WorkSettings" + ], + "summary": "출퇴근 설정 수정", + "description": "테넌트의 출퇴근 설정을 수정합니다.", + "operationId": "fec12d994b0feb6149b1fde853f569cb", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AttendanceSettingUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "수정 성공", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiResponse" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/AttendanceSetting" + } + }, + "type": "object" + } + ] + } + } + } + }, + "400": { + "description": "잘못된 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "인증 실패", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "서버 에러", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } } }, "security": [ @@ -742,6 +59217,32093 @@ } }, "components": { + "schemas": { + "AgreementItem": { + "properties": { + "type": { + "type": "string", + "example": "marketing" + }, + "label": { + "type": "string", + "example": "마케팅 정보 수신" + }, + "required": { + "type": "boolean", + "example": false + }, + "agreed": { + "type": "boolean", + "example": true + }, + "agreed_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-19T10:00:00+09:00", + "nullable": true + } + }, + "type": "object" + }, + "AgreementsResponse": { + "properties": { + "agreements": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/AgreementItem" + } + }, + "types": { + "description": "약관 유형 레이블", + "type": "object", + "example": { + "terms": "이용약관", + "privacy": "개인정보 처리방침", + "marketing": "마케팅 정보 수신" + } + } + }, + "type": "object" + }, + "WithdrawRequest": { + "required": [ + "password" + ], + "properties": { + "password": { + "description": "현재 비밀번호 (확인용)", + "type": "string", + "example": "currentPassword123" + }, + "reason": { + "description": "탈퇴 사유", + "type": "string", + "enum": [ + "not_using", + "difficult", + "alternative", + "privacy", + "other" + ], + "example": "not_using" + }, + "detail": { + "description": "상세 사유", + "type": "string", + "maxLength": 500, + "example": "더 이상 필요하지 않습니다.", + "nullable": true + } + }, + "type": "object" + }, + "WithdrawResponse": { + "properties": { + "withdrawn_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-19T10:00:00+09:00" + } + }, + "type": "object" + }, + "SuspendResponse": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + }, + "new_default_tenant_id": { + "description": "새 기본 테넌트 ID (없으면 null)", + "type": "integer", + "example": 2, + "nullable": true + } + }, + "type": "object" + }, + "UpdateAgreementsRequest": { + "required": [ + "agreements" + ], + "properties": { + "agreements": { + "type": "array", + "items": { + "required": [ + "type", + "agreed" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "terms", + "privacy", + "marketing", + "push", + "email", + "sms" + ], + "example": "marketing" + }, + "agreed": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "AdminFcmToken": { + "description": "FCM 디바이스 토큰", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "integer", + "example": 5 + }, + "token": { + "type": "string", + "example": "dGhpcyBpcyBhIHNhbXBsZSBGQ00gdG9rZW4..." + }, + "platform": { + "type": "string", + "enum": [ + "ios", + "android", + "web" + ], + "example": "android" + }, + "device_name": { + "type": "string", + "example": "Samsung Galaxy S24", + "nullable": true + }, + "app_version": { + "type": "string", + "example": "1.0.0", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "has_error": { + "type": "boolean", + "example": false + }, + "error_message": { + "type": "string", + "example": null, + "nullable": true + }, + "last_used_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:30:00", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:30:00" + }, + "user": { + "properties": { + "id": { + "type": "integer", + "example": 5 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hong@example.com" + } + }, + "type": "object", + "nullable": true + }, + "tenant": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "테스트 회사" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "AdminFcmSendLog": { + "description": "FCM 발송 이력", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "sender_id": { + "description": "발송자 ID (MNG 관리자)", + "type": "integer", + "example": 10, + "nullable": true + }, + "title": { + "type": "string", + "example": "공지사항" + }, + "body": { + "type": "string", + "example": "새로운 공지가 등록되었습니다." + }, + "channel_id": { + "type": "string", + "example": "notice", + "nullable": true + }, + "type": { + "type": "string", + "example": "notice", + "nullable": true + }, + "url": { + "type": "string", + "example": "/notices/123", + "nullable": true + }, + "total_tokens": { + "type": "integer", + "example": 150 + }, + "success_count": { + "type": "integer", + "example": 148 + }, + "failure_count": { + "type": "integer", + "example": 2 + }, + "status": { + "type": "string", + "enum": [ + "pending", + "sending", + "completed", + "failed" + ], + "example": "completed" + }, + "error_message": { + "type": "string", + "example": null, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:01:00" + }, + "tenant": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "테스트 회사" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "AdminFcmSendRequest": { + "required": [ + "title", + "body" + ], + "properties": { + "title": { + "description": "푸시 제목", + "type": "string", + "maxLength": 100, + "example": "공지사항" + }, + "body": { + "description": "푸시 내용", + "type": "string", + "maxLength": 500, + "example": "새로운 공지가 등록되었습니다." + }, + "tenant_id": { + "description": "특정 테넌트만 대상 (미지정시 전체)", + "type": "integer", + "example": 1, + "nullable": true + }, + "user_id": { + "description": "특정 사용자만 대상", + "type": "integer", + "example": 5, + "nullable": true + }, + "platform": { + "description": "특정 플랫폼만 대상", + "type": "string", + "enum": [ + "ios", + "android", + "web" + ], + "example": "android", + "nullable": true + }, + "channel_id": { + "description": "알림 채널 ID", + "type": "string", + "maxLength": 50, + "example": "notice", + "nullable": true + }, + "type": { + "description": "알림 유형", + "type": "string", + "maxLength": 50, + "example": "notice", + "nullable": true + }, + "url": { + "description": "클릭 시 이동할 URL", + "type": "string", + "maxLength": 255, + "example": "/notices/123", + "nullable": true + }, + "sound_key": { + "description": "알림음 키", + "type": "string", + "maxLength": 50, + "example": "default", + "nullable": true + } + }, + "type": "object" + }, + "AdminFcmTokenListRequest": { + "properties": { + "tenant_id": { + "description": "테넌트 ID로 필터", + "type": "integer", + "example": 1, + "nullable": true + }, + "platform": { + "description": "플랫폼으로 필터", + "type": "string", + "enum": [ + "ios", + "android", + "web" + ], + "example": "android", + "nullable": true + }, + "is_active": { + "description": "활성 상태로 필터", + "type": "boolean", + "example": true, + "nullable": true + }, + "has_error": { + "description": "에러 여부로 필터", + "type": "boolean", + "example": false, + "nullable": true + }, + "search": { + "description": "사용자명/이메일 검색", + "type": "string", + "maxLength": 100, + "example": "홍길동", + "nullable": true + }, + "per_page": { + "description": "페이지당 항목 수", + "type": "integer", + "maximum": 100, + "minimum": 1, + "example": 20 + } + }, + "type": "object" + }, + "AdminFcmHistoryRequest": { + "properties": { + "tenant_id": { + "description": "테넌트 ID로 필터", + "type": "integer", + "example": 1, + "nullable": true + }, + "status": { + "description": "발송 상태로 필터", + "type": "string", + "enum": [ + "pending", + "sending", + "completed", + "failed" + ], + "example": "completed", + "nullable": true + }, + "from": { + "description": "시작일", + "type": "string", + "format": "date", + "example": "2025-12-01", + "nullable": true + }, + "to": { + "description": "종료일", + "type": "string", + "format": "date", + "example": "2025-12-31", + "nullable": true + }, + "per_page": { + "description": "페이지당 항목 수", + "type": "integer", + "maximum": 100, + "minimum": 1, + "example": 20 + } + }, + "type": "object" + }, + "AdminFcmTokenStats": { + "description": "토큰 통계", + "properties": { + "total": { + "description": "전체 토큰 수", + "type": "integer", + "example": 500 + }, + "active": { + "description": "활성 토큰 수", + "type": "integer", + "example": 450 + }, + "inactive": { + "description": "비활성 토큰 수", + "type": "integer", + "example": 50 + }, + "has_error": { + "description": "에러 발생 토큰 수", + "type": "integer", + "example": 10 + }, + "by_platform": { + "properties": { + "android": { + "type": "integer", + "example": 300 + }, + "ios": { + "type": "integer", + "example": 180 + }, + "web": { + "type": "integer", + "example": 20 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AdminFcmTokenPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 150 + }, + "last_page": { + "type": "integer", + "example": 8 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminFcmToken" + } + } + }, + "type": "object" + }, + "AdminFcmHistoryPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminFcmSendLog" + } + } + }, + "type": "object" + }, + "GlobalMenu": { + "description": "글로벌 메뉴", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "description": "=========================\n Domain 스키마\n=========================", + "type": "integer", + "example": 1 + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "type": "string", + "example": "대시보드" + }, + "url": { + "type": "string", + "example": "/dashboard", + "nullable": true + }, + "icon": { + "type": "string", + "example": "dashboard", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "hidden": { + "type": "boolean", + "example": false + }, + "is_external": { + "type": "boolean", + "example": false + }, + "external_url": { + "type": "string", + "example": null, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-01 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-01 10:00:00" + } + }, + "type": "object" + }, + "GlobalMenuCreateRequest": { + "required": [ + "name" + ], + "properties": { + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "type": "string", + "example": "신규 메뉴" + }, + "url": { + "type": "string", + "example": "/new-menu", + "nullable": true + }, + "icon": { + "type": "string", + "example": "add", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "hidden": { + "type": "boolean", + "example": false + }, + "is_external": { + "type": "boolean", + "example": false + }, + "external_url": { + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "GlobalMenuUpdateRequest": { + "properties": { + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "type": "string", + "example": "수정된 메뉴" + }, + "url": { + "type": "string", + "example": "/updated-menu", + "nullable": true + }, + "icon": { + "type": "string", + "example": "edit", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 5 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "hidden": { + "type": "boolean", + "example": false + }, + "is_external": { + "type": "boolean", + "example": false + }, + "external_url": { + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "GlobalMenuReorderRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "required": [ + "id", + "sort_order" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "GlobalMenuStats": { + "properties": { + "total": { + "type": "integer", + "example": 25 + }, + "active": { + "type": "integer", + "example": 20 + }, + "hidden": { + "type": "integer", + "example": 3 + }, + "external": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + }, + "AiReport": { + "description": "AI 리포트", + "properties": { + "id": { + "description": "리포트 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "report_date": { + "description": "리포트 기준일", + "type": "string", + "format": "date", + "example": "2025-12-18" + }, + "report_type": { + "description": "리포트 유형", + "type": "string", + "enum": [ + "daily", + "weekly", + "monthly" + ], + "example": "daily" + }, + "content": { + "description": "리포트 내용", + "type": "array", + "items": { + "properties": { + "영역": { + "description": "분석 영역", + "type": "string", + "example": "지출분석" + }, + "상태": { + "description": "상태 코드", + "type": "string", + "enum": [ + "경고", + "주의", + "긍정", + "양호" + ], + "example": "양호" + }, + "메시지": { + "description": "핵심 메시지", + "type": "string", + "example": "당월 지출이 전월 대비 5% 감소했습니다." + }, + "상세": { + "description": "상세 설명", + "type": "string", + "example": "주요 비용 절감 항목: 외주비 (-15%), 소모품비 (-8%)" + } + }, + "type": "object" + } + }, + "summary": { + "description": "전체 요약", + "type": "string", + "example": "전반적으로 재정 상태가 양호합니다. 매출이 5% 증가하고 지출이 3% 감소했습니다." + }, + "input_data": { + "description": "입력 데이터 (비즈니스 데이터 스냅샷)", + "type": "object" + }, + "status": { + "description": "처리 상태", + "type": "string", + "enum": [ + "pending", + "completed", + "failed" + ], + "example": "completed" + }, + "error_message": { + "description": "오류 메시지 (실패 시)", + "type": "string", + "example": null, + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1 + }, + "created_at": { + "description": "생성일시", + "type": "string", + "format": "date-time", + "example": "2025-12-18T13:30:00Z" + }, + "updated_at": { + "description": "수정일시", + "type": "string", + "format": "date-time", + "example": "2025-12-18T13:30:05Z" + } + }, + "type": "object" + }, + "AiReportPagination": { + "description": "AI 리포트 페이지네이션", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiReport" + } + }, + "first_page_url": { + "type": "string", + "example": "https://api.example.com/api/v1/reports/ai?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 5 + }, + "last_page_url": { + "type": "string", + "example": "https://api.example.com/api/v1/reports/ai?page=5" + }, + "next_page_url": { + "type": "string", + "example": "https://api.example.com/api/v1/reports/ai?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "https://api.example.com/api/v1/reports/ai" + }, + "per_page": { + "type": "integer", + "example": 15 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 15 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + }, + "AiReportGenerateRequest": { + "description": "AI 리포트 생성 요청", + "properties": { + "report_date": { + "description": "리포트 기준일 (오늘 이전, 기본값: 오늘)", + "type": "string", + "format": "date", + "example": "2025-12-18" + }, + "report_type": { + "description": "리포트 유형 (기본값: daily)", + "type": "string", + "enum": [ + "daily", + "weekly", + "monthly" + ], + "example": "daily" + } + }, + "type": "object" + }, + "AiReportInputData": { + "description": "AI 리포트 입력 데이터", + "properties": { + "report_date": { + "description": "기준일", + "type": "string", + "format": "date", + "example": "2025-12-18" + }, + "report_type": { + "description": "리포트 유형", + "type": "string", + "example": "daily" + }, + "period": { + "description": "분석 기간", + "properties": { + "start": { + "type": "string", + "format": "date", + "example": "2025-12-18" + }, + "end": { + "type": "string", + "format": "date", + "example": "2025-12-18" + } + }, + "type": "object" + }, + "expense": { + "description": "지출 데이터", + "properties": { + "current_total": { + "type": "number", + "format": "float", + "example": 5000000 + }, + "previous_total": { + "type": "number", + "format": "float", + "example": 5500000 + }, + "change_rate": { + "type": "number", + "format": "float", + "example": -9.1 + } + }, + "type": "object" + }, + "sales": { + "description": "매출 데이터", + "properties": { + "current_total": { + "type": "number", + "format": "float", + "example": 10000000 + }, + "previous_total": { + "type": "number", + "format": "float", + "example": 9500000 + }, + "change_rate": { + "type": "number", + "format": "float", + "example": 5.3 + } + }, + "type": "object" + }, + "purchase": { + "description": "매입 데이터", + "properties": { + "current_total": { + "type": "number", + "format": "float", + "example": 3000000 + }, + "previous_total": { + "type": "number", + "format": "float", + "example": 2800000 + }, + "change_rate": { + "type": "number", + "format": "float", + "example": 7.1 + } + }, + "type": "object" + }, + "deposit_withdrawal": { + "description": "입출금 데이터", + "properties": { + "total_deposit": { + "type": "number", + "format": "float", + "example": 15000000 + }, + "total_withdrawal": { + "type": "number", + "format": "float", + "example": 8000000 + }, + "net_flow": { + "type": "number", + "format": "float", + "example": 7000000 + } + }, + "type": "object" + }, + "card_account": { + "description": "카드/계좌 데이터", + "properties": { + "active_cards": { + "type": "integer", + "example": 3 + }, + "current_balance": { + "type": "number", + "format": "float", + "example": 50000000 + } + }, + "type": "object" + }, + "receivable": { + "description": "미수금 데이터", + "properties": { + "total_amount": { + "type": "number", + "format": "float", + "example": 8000000 + }, + "count": { + "type": "integer", + "example": 5 + }, + "overdue_amount": { + "type": "number", + "format": "float", + "example": 2000000 + }, + "overdue_count": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Approval": { + "description": "결재 문서 정보", + "properties": { + "id": { + "description": "문서 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "form_id": { + "description": "양식 ID", + "type": "integer", + "example": 1 + }, + "drafter_id": { + "description": "기안자 ID", + "type": "integer", + "example": 10 + }, + "doc_number": { + "description": "문서번호", + "type": "string", + "example": "APR-2024-0001", + "nullable": true + }, + "title": { + "description": "제목", + "type": "string", + "example": "휴가 신청" + }, + "content": { + "description": "문서 내용 JSON", + "type": "object" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "draft", + "pending", + "approved", + "rejected", + "cancelled" + ], + "example": "pending" + }, + "current_step": { + "description": "현재 결재 단계", + "type": "integer", + "example": 1, + "nullable": true + }, + "submitted_at": { + "description": "상신일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "completed_at": { + "description": "완료일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "form": { + "description": "결재 양식 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "품의서" + }, + "code": { + "type": "string", + "example": "REQUEST_01" + } + }, + "type": "object", + "nullable": true + }, + "drafter": { + "description": "기안자 정보", + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "name": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object", + "nullable": true + }, + "steps": { + "description": "결재 단계", + "type": "array", + "items": { + "$ref": "#/components/schemas/ApprovalStepDetail" + } + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T09:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T09:00:00Z" + } + }, + "type": "object" + }, + "ApprovalStepDetail": { + "description": "결재 단계 상세 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "step_order": { + "description": "단계 순서", + "type": "integer", + "example": 1 + }, + "type": { + "description": "단계 유형", + "type": "string", + "enum": [ + "approval", + "agreement", + "reference" + ], + "example": "approval" + }, + "user_id": { + "description": "결재자 ID", + "type": "integer", + "example": 20 + }, + "status": { + "description": "단계 상태", + "type": "string", + "enum": [ + "pending", + "approved", + "rejected", + "skipped" + ], + "example": "pending" + }, + "comment": { + "description": "결재 의견", + "type": "string", + "nullable": true + }, + "acted_at": { + "description": "결재일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "is_read": { + "description": "열람 여부 (참조)", + "type": "boolean", + "example": false + }, + "read_at": { + "description": "열람일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "user": { + "description": "결재자 정보", + "properties": { + "id": { + "type": "integer", + "example": 20 + }, + "name": { + "type": "string", + "example": "김부장" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "ApprovalStoreRequest": { + "description": "결재 문서 생성/임시저장 요청", + "required": [ + "form_id", + "title" + ], + "properties": { + "form_id": { + "description": "양식 ID", + "type": "integer", + "example": 1 + }, + "title": { + "description": "제목", + "type": "string", + "example": "휴가 신청" + }, + "content": { + "description": "문서 내용 JSON", + "type": "object" + }, + "steps": { + "description": "결재 단계 (임시저장 시 선택)", + "type": "array", + "items": { + "properties": { + "type": { + "type": "string", + "enum": [ + "approval", + "agreement", + "reference" + ], + "example": "approval" + }, + "user_id": { + "type": "integer", + "example": 20 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "ApprovalUpdateRequest": { + "description": "결재 문서 수정 요청 (임시저장 상태만 가능)", + "properties": { + "title": { + "description": "제목", + "type": "string", + "example": "휴가 신청 (수정)" + }, + "content": { + "description": "문서 내용 JSON", + "type": "object" + }, + "steps": { + "description": "결재 단계", + "type": "array", + "items": { + "type": "object" + } + } + }, + "type": "object" + }, + "ApprovalSubmitRequest": { + "description": "결재 상신 요청", + "required": [ + "steps" + ], + "properties": { + "steps": { + "description": "결재 단계 (필수)", + "type": "array", + "items": { + "properties": { + "type": { + "type": "string", + "enum": [ + "approval", + "agreement", + "reference" + ], + "example": "approval" + }, + "user_id": { + "type": "integer", + "example": 20 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "ApprovalSummary": { + "description": "결재 현황 요약", + "properties": { + "draft": { + "description": "임시저장", + "type": "integer", + "example": 3 + }, + "pending": { + "description": "진행중", + "type": "integer", + "example": 5 + }, + "approved": { + "description": "승인완료", + "type": "integer", + "example": 10 + }, + "rejected": { + "description": "반려", + "type": "integer", + "example": 2 + } + }, + "type": "object" + }, + "InboxSummary": { + "description": "결재함 현황 요약", + "properties": { + "requested": { + "description": "결재 요청", + "type": "integer", + "example": 3 + }, + "scheduled": { + "description": "결재 예정", + "type": "integer", + "example": 2 + }, + "completed": { + "description": "결재 완료", + "type": "integer", + "example": 15 + }, + "rejected": { + "description": "반려", + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "ApprovalForm": { + "description": "결재 양식 정보", + "properties": { + "id": { + "description": "양식 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "양식명", + "type": "string", + "example": "품의서" + }, + "code": { + "description": "양식 코드", + "type": "string", + "example": "REQUEST_01" + }, + "category": { + "description": "카테고리", + "type": "string", + "enum": [ + "request", + "expense", + "expense_estimate" + ], + "example": "request", + "nullable": true + }, + "template": { + "description": "템플릿 JSON", + "properties": { + "fields": { + "type": "array", + "items": { + "properties": { + "name": { + "type": "string", + "example": "title" + }, + "type": { + "type": "string", + "example": "text" + }, + "label": { + "type": "string", + "example": "제목" + }, + "required": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + }, + "creator": { + "description": "생성자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "관리자" + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T09:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T09:00:00Z" + } + }, + "type": "object" + }, + "ApprovalFormCreateRequest": { + "description": "결재 양식 생성 요청", + "required": [ + "name", + "code", + "template" + ], + "properties": { + "name": { + "description": "양식명", + "type": "string", + "example": "품의서" + }, + "code": { + "description": "양식 코드 (영문, 숫자, _, -)", + "type": "string", + "example": "REQUEST_01" + }, + "category": { + "description": "카테고리", + "type": "string", + "enum": [ + "request", + "expense", + "expense_estimate" + ], + "example": "request" + }, + "template": { + "description": "템플릿 JSON", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object" + } + } + }, + "type": "object" + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "ApprovalFormUpdateRequest": { + "description": "결재 양식 수정 요청", + "properties": { + "name": { + "description": "양식명", + "type": "string", + "example": "품의서" + }, + "code": { + "description": "양식 코드", + "type": "string", + "example": "REQUEST_01" + }, + "category": { + "description": "카테고리", + "type": "string", + "enum": [ + "request", + "expense", + "expense_estimate" + ] + }, + "template": { + "description": "템플릿 JSON", + "type": "object" + }, + "is_active": { + "description": "활성 여부", + "type": "boolean" + } + }, + "type": "object" + }, + "ApprovalLine": { + "description": "결재선 템플릿 정보", + "properties": { + "id": { + "description": "결재선 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "결재선명", + "type": "string", + "example": "기본 결재선" + }, + "steps": { + "description": "결재 단계", + "type": "array", + "items": { + "properties": { + "type": { + "description": "단계 유형", + "type": "string", + "enum": [ + "approval", + "agreement", + "reference" + ], + "example": "approval" + }, + "user_id": { + "description": "결재자 ID", + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "is_default": { + "description": "기본 결재선 여부", + "type": "boolean", + "example": false + }, + "step_count": { + "description": "단계 수", + "type": "integer", + "example": 3 + }, + "creator": { + "description": "생성자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "관리자" + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T09:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T09:00:00Z" + } + }, + "type": "object" + }, + "ApprovalLineCreateRequest": { + "description": "결재선 생성 요청", + "required": [ + "name", + "steps" + ], + "properties": { + "name": { + "description": "결재선명", + "type": "string", + "example": "기본 결재선" + }, + "steps": { + "description": "결재 단계", + "type": "array", + "items": { + "properties": { + "type": { + "description": "단계 유형", + "type": "string", + "enum": [ + "approval", + "agreement", + "reference" + ], + "example": "approval" + }, + "user_id": { + "description": "결재자 ID", + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "is_default": { + "description": "기본 결재선 여부", + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "ApprovalLineUpdateRequest": { + "description": "결재선 수정 요청", + "properties": { + "name": { + "description": "결재선명", + "type": "string", + "example": "기본 결재선" + }, + "steps": { + "description": "결재 단계", + "type": "array", + "items": { + "type": "object" + } + }, + "is_default": { + "description": "기본 결재선 여부", + "type": "boolean" + } + }, + "type": "object" + }, + "Attendance": { + "description": "근태 정보", + "properties": { + "id": { + "description": "근태 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "user_id": { + "description": "사용자 ID", + "type": "integer", + "example": 10 + }, + "base_date": { + "description": "기준일", + "type": "string", + "format": "date", + "example": "2024-01-15" + }, + "status": { + "description": "근태 상태", + "type": "string", + "enum": [ + "onTime", + "late", + "absent", + "vacation", + "businessTrip", + "fieldWork", + "overtime", + "remote" + ], + "example": "onTime" + }, + "remarks": { + "description": "비고", + "type": "string", + "example": "외근으로 인한 지각", + "nullable": true + }, + "check_in": { + "description": "출근 시간", + "type": "string", + "example": "09:00:00", + "nullable": true + }, + "check_out": { + "description": "퇴근 시간", + "type": "string", + "example": "18:00:00", + "nullable": true + }, + "work_minutes": { + "description": "근무 시간(분)", + "type": "integer", + "example": 540, + "nullable": true + }, + "overtime_minutes": { + "description": "초과 근무 시간(분)", + "type": "integer", + "example": 60, + "nullable": true + }, + "late_minutes": { + "description": "지각 시간(분)", + "type": "integer", + "example": 15, + "nullable": true + }, + "user": { + "description": "사용자 정보", + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hong@company.com" + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-15T09:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-15T18:00:00Z" + } + }, + "type": "object" + }, + "AttendanceCreateRequest": { + "description": "근태 등록 요청", + "required": [ + "user_id", + "base_date" + ], + "properties": { + "user_id": { + "description": "사용자 ID", + "type": "integer", + "example": 10 + }, + "base_date": { + "description": "기준일", + "type": "string", + "format": "date", + "example": "2024-01-15" + }, + "status": { + "description": "근태 상태", + "type": "string", + "enum": [ + "onTime", + "late", + "absent", + "vacation", + "businessTrip", + "fieldWork", + "overtime", + "remote" + ], + "example": "onTime" + }, + "remarks": { + "description": "비고", + "type": "string", + "example": "외근으로 인한 지각" + }, + "check_in": { + "description": "출근 시간", + "type": "string", + "example": "09:00:00" + }, + "check_out": { + "description": "퇴근 시간", + "type": "string", + "example": "18:00:00" + }, + "work_minutes": { + "description": "근무 시간(분)", + "type": "integer", + "example": 540 + }, + "overtime_minutes": { + "description": "초과 근무 시간(분)", + "type": "integer", + "example": 60 + }, + "vacation_type": { + "description": "휴가 유형", + "type": "string", + "example": "annual" + } + }, + "type": "object" + }, + "AttendanceUpdateRequest": { + "description": "근태 수정 요청", + "properties": { + "status": { + "description": "근태 상태", + "type": "string", + "enum": [ + "onTime", + "late", + "absent", + "vacation", + "businessTrip", + "fieldWork", + "overtime", + "remote" + ], + "example": "onTime" + }, + "remarks": { + "description": "비고", + "type": "string", + "example": "수정된 비고" + }, + "check_in": { + "description": "출근 시간", + "type": "string", + "example": "09:00:00" + }, + "check_out": { + "description": "퇴근 시간", + "type": "string", + "example": "18:00:00" + }, + "work_minutes": { + "description": "근무 시간(분)", + "type": "integer", + "example": 540 + } + }, + "type": "object" + }, + "AttendanceMonthlyStats": { + "description": "월간 근태 통계", + "properties": { + "year": { + "type": "integer", + "example": 2024 + }, + "month": { + "type": "integer", + "example": 1 + }, + "total_days": { + "description": "총 기록 일수", + "type": "integer", + "example": 22 + }, + "by_status": { + "description": "상태별 일수", + "properties": { + "onTime": { + "type": "integer", + "example": 18 + }, + "late": { + "type": "integer", + "example": 2 + }, + "absent": { + "type": "integer", + "example": 0 + }, + "vacation": { + "type": "integer", + "example": 2 + }, + "businessTrip": { + "type": "integer", + "example": 0 + }, + "fieldWork": { + "type": "integer", + "example": 0 + }, + "overtime": { + "type": "integer", + "example": 0 + }, + "remote": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "total_work_minutes": { + "description": "총 근무 시간(분)", + "type": "integer", + "example": 11880 + }, + "total_overtime_minutes": { + "description": "총 초과 근무 시간(분)", + "type": "integer", + "example": 300 + } + }, + "type": "object" + }, + "SignupRequest": { + "required": [ + "user_id", + "name", + "email", + "password" + ], + "properties": { + "user_id": { + "description": "로그인 ID (고유)", + "type": "string", + "maxLength": 255, + "example": "userId" + }, + "name": { + "type": "string", + "maxLength": 255, + "example": "Kent" + }, + "email": { + "type": "string", + "maxLength": 100, + "example": "codebridge@gmail.com" + }, + "phone": { + "type": "string", + "maxLength": 30, + "example": "010-4820-9104", + "nullable": true + }, + "password": { + "type": "string", + "maxLength": 64, + "minLength": 8, + "example": "StrongPass!1234" + } + }, + "type": "object" + }, + "SignupResponseData": { + "properties": { + "user": { + "$ref": "#/components/schemas/Member" + } + }, + "type": "object" + }, + "MemberBrief": { + "description": "회원 요약 정보(회원가입 응답용)", + "required": [ + "id", + "user_id", + "name", + "email", + "phone" + ], + "properties": { + "id": { + "type": "integer", + "example": 6 + }, + "user_id": { + "type": "string", + "example": "userId" + }, + "name": { + "type": "string", + "example": "Kent" + }, + "email": { + "type": "string", + "example": "codebridge1@gmail.com" + }, + "phone": { + "type": "string", + "example": "010-4820-9104" + } + }, + "type": "object" + }, + "BadDebt": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "client_id": { + "type": "integer", + "example": 1 + }, + "debt_amount": { + "type": "number", + "format": "decimal", + "example": "10000000.00" + }, + "status": { + "type": "string", + "enum": [ + "collecting", + "legal_action", + "recovered", + "bad_debt" + ], + "example": "collecting" + }, + "overdue_days": { + "type": "integer", + "example": 100 + }, + "assigned_user_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "occurred_at": { + "type": "string", + "format": "date", + "example": "2025-12-12", + "nullable": true + }, + "closed_at": { + "type": "string", + "format": "date", + "example": null, + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "options": { + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "client": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "client_code": { + "type": "string" + } + }, + "type": "object" + }, + "assigned_user": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "BadDebtPagination": { + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BadDebt" + } + } + }, + "type": "object" + } + ] + }, + "BadDebtSummary": { + "properties": { + "total_amount": { + "type": "number", + "example": 50000000 + }, + "collecting_amount": { + "type": "number", + "example": 30000000 + }, + "legal_action_amount": { + "type": "number", + "example": 10000000 + }, + "recovered_amount": { + "type": "number", + "example": 5000000 + }, + "bad_debt_amount": { + "type": "number", + "example": 5000000 + } + }, + "type": "object" + }, + "BadDebtCreateRequest": { + "required": [ + "client_id", + "debt_amount" + ], + "properties": { + "client_id": { + "type": "integer", + "example": 1 + }, + "debt_amount": { + "type": "number", + "example": 10000000 + }, + "status": { + "type": "string", + "enum": [ + "collecting", + "legal_action", + "recovered", + "bad_debt" + ], + "example": "collecting" + }, + "overdue_days": { + "type": "integer", + "example": 100 + }, + "assigned_user_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "occurred_at": { + "type": "string", + "format": "date", + "example": "2025-12-12", + "nullable": true + }, + "closed_at": { + "type": "string", + "format": "date", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "options": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "BadDebtUpdateRequest": { + "properties": { + "client_id": { + "type": "integer", + "example": 1 + }, + "debt_amount": { + "type": "number", + "example": 10000000 + }, + "status": { + "type": "string", + "enum": [ + "collecting", + "legal_action", + "recovered", + "bad_debt" + ], + "example": "legal_action" + }, + "overdue_days": { + "type": "integer", + "example": 120 + }, + "assigned_user_id": { + "type": "integer", + "example": 2, + "nullable": true + }, + "occurred_at": { + "type": "string", + "format": "date", + "nullable": true + }, + "closed_at": { + "type": "string", + "format": "date", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "options": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "BadDebtDocument": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "bad_debt_id": { + "type": "integer", + "example": 1 + }, + "document_type": { + "type": "string", + "enum": [ + "business_license", + "tax_invoice", + "additional" + ], + "example": "business_license" + }, + "file_id": { + "type": "integer", + "example": 1 + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "file": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "BadDebtDocumentCreateRequest": { + "required": [ + "document_type", + "file_id" + ], + "properties": { + "document_type": { + "type": "string", + "enum": [ + "business_license", + "tax_invoice", + "additional" + ], + "example": "business_license" + }, + "file_id": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "BadDebtMemo": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "bad_debt_id": { + "type": "integer", + "example": 1 + }, + "content": { + "type": "string", + "example": "2025-12-12 홍길동 과장님 메모 내용" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "creator": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "BadDebtMemoCreateRequest": { + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string", + "maxLength": 5000, + "example": "메모 내용" + } + }, + "type": "object" + }, + "BankAccount": { + "description": "계좌 정보", + "properties": { + "id": { + "description": "계좌 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "bank_code": { + "description": "은행 코드", + "type": "string", + "example": "088" + }, + "bank_name": { + "description": "은행명", + "type": "string", + "example": "신한은행" + }, + "account_number": { + "description": "계좌번호", + "type": "string", + "example": "110-123-456789" + }, + "account_holder": { + "description": "예금주", + "type": "string", + "example": "주식회사 샘" + }, + "account_name": { + "description": "계좌 별칭", + "type": "string", + "example": "운영계좌" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "active" + }, + "assigned_user_id": { + "description": "담당자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "assigned_user": { + "description": "담당자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object", + "nullable": true + }, + "is_primary": { + "description": "대표계좌 여부", + "type": "boolean", + "example": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "description": "수정자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "BankAccountCreateRequest": { + "description": "계좌 등록 요청", + "required": [ + "bank_code", + "bank_name", + "account_number", + "account_holder", + "account_name" + ], + "properties": { + "bank_code": { + "description": "은행 코드", + "type": "string", + "maxLength": 10, + "example": "088" + }, + "bank_name": { + "description": "은행명", + "type": "string", + "maxLength": 50, + "example": "신한은행" + }, + "account_number": { + "description": "계좌번호", + "type": "string", + "maxLength": 30, + "example": "110-123-456789" + }, + "account_holder": { + "description": "예금주", + "type": "string", + "maxLength": 50, + "example": "주식회사 샘" + }, + "account_name": { + "description": "계좌 별칭", + "type": "string", + "maxLength": 100, + "example": "운영계좌" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "active" + }, + "assigned_user_id": { + "description": "담당자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "is_primary": { + "description": "대표계좌 여부", + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "BankAccountUpdateRequest": { + "description": "계좌 수정 요청", + "properties": { + "bank_code": { + "description": "은행 코드", + "type": "string", + "maxLength": 10, + "example": "088" + }, + "bank_name": { + "description": "은행명", + "type": "string", + "maxLength": 50, + "example": "신한은행" + }, + "account_number": { + "description": "계좌번호", + "type": "string", + "maxLength": 30, + "example": "110-123-456789" + }, + "account_holder": { + "description": "예금주", + "type": "string", + "maxLength": 50, + "example": "주식회사 샘" + }, + "account_name": { + "description": "계좌 별칭", + "type": "string", + "maxLength": 100, + "example": "운영계좌" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "active" + }, + "assigned_user_id": { + "description": "담당자 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "BankAccountListItem": { + "description": "계좌 목록 아이템 (셀렉트박스용)", + "properties": { + "id": { + "description": "계좌 ID", + "type": "integer", + "example": 1 + }, + "account_name": { + "description": "계좌 별칭", + "type": "string", + "example": "운영계좌" + }, + "bank_name": { + "description": "은행명", + "type": "string", + "example": "신한은행" + }, + "display_number": { + "description": "마스킹된 계좌번호", + "type": "string", + "example": "*****6789" + }, + "is_primary": { + "description": "대표계좌 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "BankTransactionItem": { + "description": "은행 거래 항목", + "properties": { + "id": { + "description": "거래 ID", + "type": "integer", + "example": 1 + }, + "type": { + "description": "구분", + "type": "string", + "enum": [ + "deposit", + "withdrawal" + ], + "example": "deposit" + }, + "transaction_date": { + "description": "거래일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "bank_account_id": { + "description": "계좌 ID", + "type": "integer", + "example": 1 + }, + "bank_name": { + "description": "은행명", + "type": "string", + "example": "국민은행" + }, + "account_name": { + "description": "계좌명", + "type": "string", + "example": "영업계좌" + }, + "note": { + "description": "적요", + "type": "string", + "example": "거래 메모", + "nullable": true + }, + "vendor_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "vendor_name": { + "description": "거래처명", + "type": "string", + "example": "(주)삼성전자", + "nullable": true + }, + "depositor_name": { + "description": "입금자/수취인", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "deposit_amount": { + "description": "입금액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "withdrawal_amount": { + "description": "출금액", + "type": "number", + "format": "float", + "example": 0 + }, + "balance": { + "description": "잔액", + "type": "number", + "format": "float", + "example": 50000000 + }, + "transaction_type": { + "description": "입출금 유형", + "type": "string", + "example": "salesRevenue", + "nullable": true + }, + "source_id": { + "description": "원본 ID", + "type": "string", + "example": "deposit-1" + }, + "created_at": { + "description": "생성일시", + "type": "string", + "format": "date-time" + }, + "updated_at": { + "description": "수정일시", + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "BankTransactionSummary": { + "description": "은행 거래 요약 통계", + "properties": { + "total_deposit": { + "description": "총 입금액", + "type": "number", + "format": "float", + "example": 15000000 + }, + "total_withdrawal": { + "description": "총 출금액", + "type": "number", + "format": "float", + "example": 8500000 + }, + "deposit_unset_count": { + "description": "입금 유형 미설정 건수", + "type": "integer", + "example": 5 + }, + "withdrawal_unset_count": { + "description": "출금 유형 미설정 건수", + "type": "integer", + "example": 3 + } + }, + "type": "object" + }, + "BankTransactionPagination": { + "description": "은행 거래 목록 페이지네이션", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BankTransactionItem" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "last_page_url": { + "type": "string" + }, + "next_page_url": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer" + }, + "prev_page_url": { + "type": "string", + "nullable": true + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + }, + "type": "object" + }, + "BankAccountOption": { + "description": "계좌 선택 옵션", + "properties": { + "id": { + "description": "계좌 ID", + "type": "integer", + "example": 1 + }, + "label": { + "description": "표시명", + "type": "string", + "example": "국민은행|영업계좌" + } + }, + "type": "object" + }, + "BarobillSetting": { + "description": "바로빌 설정 정보", + "properties": { + "id": { + "description": "설정 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "corp_num": { + "description": "사업자번호 (10자리)", + "type": "string", + "example": "1234567890" + }, + "barobill_id": { + "description": "바로빌 아이디", + "type": "string", + "example": "testuser" + }, + "corp_name": { + "description": "회사명", + "type": "string", + "example": "(주)테스트회사" + }, + "ceo_name": { + "description": "대표자명", + "type": "string", + "example": "홍길동" + }, + "addr": { + "description": "주소", + "type": "string", + "example": "서울시 강남구 테헤란로 123", + "nullable": true + }, + "biz_type": { + "description": "업태", + "type": "string", + "example": "서비스", + "nullable": true + }, + "biz_class": { + "description": "종목", + "type": "string", + "example": "소프트웨어개발", + "nullable": true + }, + "contact_id": { + "description": "담당자 이메일", + "type": "string", + "example": "manager@test.com", + "nullable": true + }, + "contact_name": { + "description": "담당자명", + "type": "string", + "example": "김담당", + "nullable": true + }, + "contact_tel": { + "description": "담당자 연락처", + "type": "string", + "example": "02-1234-5678", + "nullable": true + }, + "is_active": { + "description": "활성화 여부", + "type": "boolean", + "example": true + }, + "auto_issue": { + "description": "자동발행 여부", + "type": "boolean", + "example": false + }, + "verified_at": { + "description": "검증 완료 일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "formatted_corp_num": { + "description": "포맷팅된 사업자번호", + "type": "string", + "example": "123-45-67890" + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "description": "수정자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "BarobillSettingSaveRequest": { + "description": "바로빌 설정 저장 요청", + "required": [ + "corp_num", + "cert_key", + "barobill_id", + "corp_name", + "ceo_name" + ], + "properties": { + "corp_num": { + "description": "사업자번호 (10자리, 하이픈 제외)", + "type": "string", + "maxLength": 10, + "minLength": 10, + "example": "1234567890" + }, + "cert_key": { + "description": "공인인증서 키 (암호화되어 저장)", + "type": "string", + "example": "xxxxxx" + }, + "barobill_id": { + "description": "바로빌 아이디", + "type": "string", + "maxLength": 50, + "example": "testuser" + }, + "corp_name": { + "description": "회사명", + "type": "string", + "maxLength": 200, + "example": "(주)테스트회사" + }, + "ceo_name": { + "description": "대표자명", + "type": "string", + "maxLength": 100, + "example": "홍길동" + }, + "addr": { + "description": "주소", + "type": "string", + "maxLength": 500, + "example": "서울시 강남구 테헤란로 123", + "nullable": true + }, + "biz_type": { + "description": "업태", + "type": "string", + "maxLength": 100, + "example": "서비스", + "nullable": true + }, + "biz_class": { + "description": "종목", + "type": "string", + "maxLength": 100, + "example": "소프트웨어개발", + "nullable": true + }, + "contact_id": { + "description": "담당자 이메일", + "type": "string", + "maxLength": 100, + "example": "manager@test.com", + "nullable": true + }, + "contact_name": { + "description": "담당자명", + "type": "string", + "maxLength": 100, + "example": "김담당", + "nullable": true + }, + "contact_tel": { + "description": "담당자 연락처", + "type": "string", + "maxLength": 50, + "example": "02-1234-5678", + "nullable": true + }, + "is_active": { + "description": "활성화 여부 (기본값: true)", + "type": "boolean", + "example": true + }, + "auto_issue": { + "description": "자동발행 여부 (기본값: false)", + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "BarobillConnectionTestResult": { + "description": "바로빌 연동 테스트 결과", + "properties": { + "success": { + "description": "연동 성공 여부", + "type": "boolean", + "example": true + }, + "remaining_point": { + "description": "잔여 포인트", + "type": "integer", + "example": 10000 + }, + "tested_at": { + "description": "테스트 일시", + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "Bidding": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "bidding_code": { + "type": "string", + "example": "BID-20260119-0001" + }, + "quote_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "client_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "type": "string", + "example": "삼성물산", + "nullable": true + }, + "project_name": { + "type": "string", + "example": "강남역 오피스타워 신축공사", + "nullable": true + }, + "bidding_date": { + "type": "string", + "format": "date", + "example": "2026-01-19", + "nullable": true + }, + "bid_date": { + "type": "string", + "format": "date", + "example": "2026-02-01", + "nullable": true + }, + "submission_date": { + "type": "string", + "format": "date", + "example": "2026-01-25", + "nullable": true + }, + "confirm_date": { + "type": "string", + "format": "date", + "example": "2026-02-15", + "nullable": true + }, + "total_count": { + "type": "integer", + "example": 1, + "nullable": true + }, + "bidding_amount": { + "type": "number", + "format": "float", + "example": 150000000, + "nullable": true + }, + "status": { + "type": "string", + "enum": [ + "waiting", + "submitted", + "failed", + "invalid", + "awarded", + "hold" + ], + "example": "waiting" + }, + "bidder_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "bidder_name": { + "type": "string", + "example": "홍길동", + "nullable": true + }, + "construction_start_date": { + "type": "string", + "format": "date", + "example": "2026-03-01", + "nullable": true + }, + "construction_end_date": { + "type": "string", + "format": "date", + "example": "2026-12-31", + "nullable": true + }, + "vat_type": { + "type": "string", + "enum": [ + "included", + "excluded" + ], + "example": "included" + }, + "remarks": { + "type": "string", + "example": "특이사항 없음", + "nullable": true + }, + "expense_items": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true + }, + "estimate_detail_items": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true + }, + "created_by": { + "type": "integer", + "nullable": true + }, + "updated_by": { + "type": "integer", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "quote": { + "type": "object", + "nullable": true + }, + "client": { + "type": "object", + "nullable": true + }, + "bidder": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "BiddingPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bidding" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "last_page_url": { + "type": "string" + }, + "next_page_url": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer" + }, + "prev_page_url": { + "type": "string", + "nullable": true + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + }, + "type": "object" + }, + "BiddingStats": { + "properties": { + "total": { + "type": "integer", + "example": 100 + }, + "waiting": { + "type": "integer", + "example": 30 + }, + "submitted": { + "type": "integer", + "example": 20 + }, + "failed": { + "type": "integer", + "example": 10 + }, + "invalid": { + "type": "integer", + "example": 5 + }, + "awarded": { + "type": "integer", + "example": 30 + }, + "hold": { + "type": "integer", + "example": 5 + }, + "total_amount": { + "type": "number", + "format": "float", + "example": 5000000000 + }, + "awarded_amount": { + "type": "number", + "format": "float", + "example": 3000000000 + } + }, + "type": "object" + }, + "BiddingUpdateRequest": { + "properties": { + "client_id": { + "type": "integer", + "nullable": true + }, + "client_name": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "project_name": { + "type": "string", + "maxLength": 200, + "nullable": true + }, + "bidding_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "bid_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "submission_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "confirm_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "total_count": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "bidding_amount": { + "type": "number", + "format": "float", + "minimum": 0, + "nullable": true + }, + "status": { + "type": "string", + "enum": [ + "waiting", + "submitted", + "failed", + "invalid", + "awarded", + "hold" + ], + "nullable": true + }, + "bidder_id": { + "type": "integer", + "nullable": true + }, + "bidder_name": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "construction_start_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "construction_end_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "vat_type": { + "type": "string", + "enum": [ + "included", + "excluded" + ], + "nullable": true + }, + "remarks": { + "type": "string", + "nullable": true + }, + "expense_items": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true + }, + "estimate_detail_items": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true + } + }, + "type": "object" + }, + "BiddingStatusRequest": { + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "waiting", + "submitted", + "failed", + "invalid", + "awarded", + "hold" + ], + "example": "submitted" + } + }, + "type": "object" + }, + "BiddingBulkDeleteRequest": { + "required": [ + "ids" + ], + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + } + }, + "type": "object" + }, + "Bill": { + "required": [ + "id", + "tenant_id", + "bill_number", + "bill_type", + "amount", + "issue_date", + "maturity_date", + "status" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "bill_number": { + "description": "어음번호", + "type": "string", + "example": "202412000001" + }, + "bill_type": { + "description": "어음 구분: received=수취, issued=발행", + "type": "string", + "enum": [ + "received", + "issued" + ], + "example": "received" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 10, + "nullable": true + }, + "client_name": { + "description": "거래처명 (비회원용)", + "type": "string", + "example": "(주)삼성전자", + "nullable": true + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 10000000 + }, + "issue_date": { + "description": "발행일", + "type": "string", + "format": "date", + "example": "2024-12-01" + }, + "maturity_date": { + "description": "만기일", + "type": "string", + "format": "date", + "example": "2025-03-01" + }, + "status": { + "description": "상태: stored/maturityAlert/maturityResult/paymentComplete/dishonored/collectionRequest/collectionComplete/suing", + "type": "string", + "example": "stored" + }, + "reason": { + "description": "사유", + "type": "string", + "example": "거래 대금", + "nullable": true + }, + "installment_count": { + "description": "차수", + "type": "integer", + "example": 0 + }, + "note": { + "description": "메모/비고", + "type": "string", + "example": "메모 내용", + "nullable": true + }, + "is_electronic": { + "description": "전자어음 여부", + "type": "boolean", + "example": false + }, + "bank_account_id": { + "description": "입금/출금 계좌 ID", + "type": "integer", + "example": 5, + "nullable": true + }, + "created_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "client": { + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "name": { + "type": "string", + "example": "(주)삼성전자" + } + }, + "type": "object", + "nullable": true + }, + "bank_account": { + "properties": { + "id": { + "type": "integer", + "example": 5 + }, + "bank_name": { + "type": "string", + "example": "국민은행" + }, + "account_name": { + "type": "string", + "example": "운영계좌" + } + }, + "type": "object", + "nullable": true + }, + "installments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BillInstallment" + } + } + }, + "type": "object" + }, + "BillInstallment": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "bill_id": { + "type": "integer", + "example": 1 + }, + "installment_date": { + "description": "차수 일자", + "type": "string", + "format": "date", + "example": "2024-12-15" + }, + "amount": { + "description": "차수 금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "note": { + "description": "비고", + "type": "string", + "example": "1차 분할", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "BillPagination": { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bill" + } + }, + "current_page": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 5 + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 100 + }, + "from": { + "type": "integer", + "example": 1 + }, + "to": { + "type": "integer", + "example": 20 + } + }, + "type": "object" + }, + "BillCreateRequest": { + "required": [ + "bill_type", + "amount", + "issue_date", + "maturity_date" + ], + "properties": { + "bill_number": { + "description": "어음번호 (미입력시 자동생성)", + "type": "string", + "example": "202412000001", + "nullable": true + }, + "bill_type": { + "description": "어음 구분", + "type": "string", + "enum": [ + "received", + "issued" + ], + "example": "received" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 10, + "nullable": true + }, + "client_name": { + "description": "거래처명", + "type": "string", + "example": "(주)삼성전자", + "nullable": true + }, + "amount": { + "description": "금액", + "type": "number", + "example": 10000000 + }, + "issue_date": { + "description": "발행일", + "type": "string", + "format": "date", + "example": "2024-12-01" + }, + "maturity_date": { + "description": "만기일", + "type": "string", + "format": "date", + "example": "2025-03-01" + }, + "status": { + "description": "상태", + "type": "string", + "example": "stored", + "nullable": true + }, + "reason": { + "description": "사유", + "type": "string", + "example": "거래 대금", + "nullable": true + }, + "note": { + "description": "메모", + "type": "string", + "example": "메모 내용", + "nullable": true + }, + "is_electronic": { + "description": "전자어음 여부", + "type": "boolean", + "example": false, + "nullable": true + }, + "bank_account_id": { + "description": "계좌 ID", + "type": "integer", + "example": 5, + "nullable": true + }, + "installments": { + "type": "array", + "items": { + "properties": { + "date": { + "type": "string", + "format": "date", + "example": "2024-12-15" + }, + "amount": { + "type": "number", + "example": 5000000 + }, + "note": { + "type": "string", + "example": "1차 분할", + "nullable": true + } + }, + "type": "object" + }, + "nullable": true + } + }, + "type": "object" + }, + "BillUpdateRequest": { + "properties": { + "bill_number": { + "type": "string", + "example": "202412000001", + "nullable": true + }, + "bill_type": { + "type": "string", + "enum": [ + "received", + "issued" + ], + "nullable": true + }, + "client_id": { + "type": "integer", + "nullable": true + }, + "client_name": { + "type": "string", + "nullable": true + }, + "amount": { + "type": "number", + "nullable": true + }, + "issue_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "maturity_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "status": { + "type": "string", + "nullable": true + }, + "reason": { + "type": "string", + "nullable": true + }, + "note": { + "type": "string", + "nullable": true + }, + "is_electronic": { + "type": "boolean", + "nullable": true + }, + "bank_account_id": { + "type": "integer", + "nullable": true + }, + "installments": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true + } + }, + "type": "object" + }, + "BillSummary": { + "properties": { + "total_amount": { + "description": "총 금액", + "type": "number", + "example": 50000000 + }, + "total_count": { + "description": "총 건수", + "type": "integer", + "example": 10 + }, + "by_type": { + "description": "구분별 합계", + "type": "object", + "additionalProperties": { + "properties": { + "bill_type": { + "type": "string" + }, + "total": { + "type": "number" + }, + "count": { + "type": "integer" + } + }, + "type": "object" + } + }, + "by_status": { + "description": "상태별 합계", + "type": "object" + }, + "maturity_alert_amount": { + "description": "만기 임박 금액 (7일 이내)", + "type": "number", + "example": 10000000 + } + }, + "type": "object" + }, + "BillDashboardDetail": { + "description": "발행어음 대시보드 상세 (CEO 대시보드 당월 예상 지출내역 me3 모달용)", + "properties": { + "summary": { + "description": "요약 정보", + "properties": { + "current_month_total": { + "description": "당월 발행어음 합계", + "type": "number", + "example": 50000000 + }, + "previous_month_total": { + "description": "전월 발행어음 합계", + "type": "number", + "example": 45000000 + }, + "change_rate": { + "description": "전월 대비 증감율 (%)", + "type": "number", + "example": 11.1 + } + }, + "type": "object" + }, + "monthly_trend": { + "description": "월별 추이 (최근 7개월)", + "type": "array", + "items": { + "properties": { + "month": { + "description": "년-월", + "type": "string", + "example": "2025-07" + }, + "amount": { + "description": "해당 월 발행어음 합계", + "type": "number", + "example": 42000000 + } + }, + "type": "object" + } + }, + "by_vendor": { + "description": "거래처별 분포 (당월)", + "type": "array", + "items": { + "properties": { + "vendor_name": { + "description": "거래처명", + "type": "string", + "example": "(주)삼성전자" + }, + "amount": { + "description": "금액", + "type": "number", + "example": 25000000 + }, + "percentage": { + "description": "비율 (%)", + "type": "number", + "example": 50 + } + }, + "type": "object" + } + }, + "items": { + "description": "발행어음 목록 (당월)", + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "vendor": { + "description": "거래처명", + "type": "string", + "example": "(주)삼성전자" + }, + "issue_date": { + "description": "발행일", + "type": "string", + "format": "date", + "example": "2025-01-05" + }, + "due_date": { + "description": "만기일", + "type": "string", + "format": "date", + "example": "2025-04-05" + }, + "amount": { + "description": "금액", + "type": "number", + "example": 10000000 + }, + "status": { + "description": "상태", + "type": "string", + "example": "stored" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "Board": { + "required": [ + "id", + "board_code", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID (시스템 게시판은 null)", + "type": "integer", + "example": 1, + "nullable": true + }, + "is_system": { + "description": "시스템 게시판 여부", + "type": "boolean", + "example": false + }, + "board_type": { + "description": "게시판 유형 (notice, qna, faq 등)", + "type": "string", + "example": "notice", + "nullable": true + }, + "board_code": { + "description": "게시판 코드", + "type": "string", + "example": "NOTICE" + }, + "name": { + "description": "게시판명", + "type": "string", + "example": "공지사항" + }, + "description": { + "description": "설명", + "type": "string", + "example": "전사 공지사항 게시판", + "nullable": true + }, + "editor_type": { + "description": "에디터 타입", + "type": "string", + "enum": [ + "wysiwyg", + "markdown", + "text" + ], + "example": "wysiwyg" + }, + "allow_files": { + "description": "파일 첨부 허용", + "type": "boolean", + "example": true + }, + "max_file_count": { + "description": "최대 파일 수", + "type": "integer", + "example": 5 + }, + "max_file_size": { + "description": "최대 파일 크기 (KB)", + "type": "integer", + "example": 20480 + }, + "extra_settings": { + "description": "추가 설정", + "type": "object", + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "example": "2025-01-01 12:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-01-01 12:00:00" + } + }, + "type": "object" + }, + "BoardField": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "board_id": { + "type": "integer", + "example": 1 + }, + "field_key": { + "description": "필드 키", + "type": "string", + "example": "category" + }, + "field_label": { + "description": "필드 라벨", + "type": "string", + "example": "카테고리" + }, + "field_type": { + "description": "필드 타입", + "type": "string", + "example": "select" + }, + "is_required": { + "type": "boolean", + "example": false + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "options": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "BoardCreateRequest": { + "required": [ + "board_code", + "name" + ], + "properties": { + "board_code": { + "type": "string", + "maxLength": 50, + "example": "NOTICE" + }, + "board_type": { + "type": "string", + "maxLength": 50, + "example": "notice", + "nullable": true + }, + "name": { + "type": "string", + "maxLength": 100, + "example": "공지사항" + }, + "description": { + "type": "string", + "maxLength": 500, + "nullable": true + }, + "editor_type": { + "type": "string", + "enum": [ + "wysiwyg", + "markdown", + "text" + ], + "example": "wysiwyg" + }, + "allow_files": { + "type": "boolean", + "example": true + }, + "max_file_count": { + "type": "integer", + "example": 5 + }, + "max_file_size": { + "type": "integer", + "example": 20480 + }, + "extra_settings": { + "type": "object", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "BoardUpdateRequest": { + "properties": { + "board_code": { + "type": "string", + "maxLength": 50 + }, + "board_type": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "description": { + "type": "string", + "maxLength": 500, + "nullable": true + }, + "editor_type": { + "type": "string", + "enum": [ + "wysiwyg", + "markdown", + "text" + ] + }, + "allow_files": { + "type": "boolean" + }, + "max_file_count": { + "type": "integer" + }, + "max_file_size": { + "type": "integer" + }, + "extra_settings": { + "type": "object", + "nullable": true + }, + "is_active": { + "type": "boolean" + } + }, + "type": "object" + }, + "EstimateParametersResponse": { + "required": [ + "success", + "message", + "data" + ], + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "견적 파라미터를 성공적으로 조회했습니다." + }, + "data": { + "properties": { + "model_info": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "스크린셔터 표준형" + }, + "version": { + "type": "string", + "example": "v1.0" + }, + "bom_template_id": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "company_info": { + "properties": { + "company_type": { + "type": "string", + "example": "경동기업" + }, + "formula_version": { + "type": "string", + "example": "v2.0" + }, + "requested_company": { + "type": "string", + "example": "경동기업" + } + }, + "type": "object" + }, + "parameters": { + "properties": { + "required_parameters": { + "type": "array", + "items": { + "properties": { + "key": { + "type": "string", + "example": "W0" + }, + "label": { + "type": "string", + "example": "오픈사이즈 가로(mm)" + }, + "type": { + "type": "string", + "example": "integer" + }, + "required": { + "type": "boolean", + "example": true + }, + "min": { + "type": "integer", + "example": 500 + }, + "max": { + "type": "integer", + "example": 15000 + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "CalculateBomRequest": { + "required": [ + "parameters" + ], + "properties": { + "parameters": { + "properties": { + "W0": { + "type": "integer", + "example": 3000 + }, + "H0": { + "type": "integer", + "example": 2500 + }, + "product_type": { + "type": "string", + "example": "screen" + } + }, + "type": "object" + }, + "company_name": { + "type": "string", + "example": "경동기업" + } + }, + "type": "object" + }, + "CalculateBomResponse": { + "required": [ + "success", + "message", + "data" + ], + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "BOM 계산이 완료되었습니다." + }, + "data": { + "properties": { + "bom_template": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "Main" + }, + "company_type": { + "type": "string", + "example": "경동기업" + }, + "formula_version": { + "type": "string", + "example": "v2.0" + } + }, + "type": "object" + }, + "input_parameters": { + "properties": { + "W0": { + "type": "integer", + "example": 3000 + }, + "H0": { + "type": "integer", + "example": 2500 + }, + "product_type": { + "type": "string", + "example": "screen" + } + }, + "type": "object" + }, + "calculated_values": { + "properties": { + "W1": { + "type": "integer", + "example": 3160 + }, + "H1": { + "type": "integer", + "example": 2850 + }, + "area": { + "type": "number", + "format": "float", + "example": 9.006 + }, + "weight": { + "type": "number", + "format": "float", + "example": 60.42 + } + }, + "type": "object" + }, + "bom_items": { + "type": "array", + "items": { + "properties": { + "item_id": { + "type": "integer", + "example": 1 + }, + "ref_type": { + "type": "string", + "example": "MATERIAL" + }, + "ref_id": { + "type": "integer", + "example": 101 + }, + "original_qty": { + "type": "integer", + "example": 1 + }, + "calculated_qty": { + "type": "integer", + "example": 2 + }, + "is_calculated": { + "type": "boolean", + "example": true + }, + "calculation_formula": { + "type": "string", + "example": "bracket_quantity" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + }, + "CompanyFormulasResponse": { + "required": [ + "success", + "message", + "data" + ], + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "업체 산출식 목록을 조회했습니다." + }, + "data": { + "properties": { + "company_name": { + "type": "string", + "example": "경동기업" + }, + "total_formulas": { + "type": "integer", + "example": 5 + }, + "formulas": { + "type": "array", + "items": { + "properties": { + "type": { + "type": "string", + "example": "manufacturing_size" + }, + "version": { + "type": "string", + "example": "v2.0" + }, + "description": { + "type": "string", + "example": "제작사이즈 계산식" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-09-22T15:30:00Z" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SaveFormulaRequest": { + "required": [ + "formula_expression", + "parameters" + ], + "properties": { + "formula_expression": { + "type": "string", + "example": "bracket_quantity" + }, + "parameters": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "W1", + "H1" + ] + }, + "conditions": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "product_type=screen" + ] + }, + "validation_rules": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "W1>0", + "H1>0" + ] + }, + "description": { + "type": "string", + "example": "브라켓 수량 계산식" + } + }, + "type": "object" + }, + "FormulaTestRequest": { + "required": [ + "formula_expression", + "test_parameters" + ], + "properties": { + "formula_expression": { + "type": "string", + "example": "bracket_quantity" + }, + "test_parameters": { + "properties": { + "W1": { + "type": "integer", + "example": 3000 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "FormulaTestResponse": { + "required": [ + "success", + "message", + "data" + ], + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "계산식 테스트가 완료되었습니다." + }, + "data": { + "properties": { + "formula_expression": { + "type": "string", + "example": "bracket_quantity" + }, + "input_parameters": { + "properties": { + "W1": { + "type": "integer", + "example": 3000 + } + }, + "type": "object" + }, + "result": { + "properties": { + "result": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + }, + "execution_time_ms": { + "type": "number", + "format": "float", + "example": 1.5 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "CalendarScheduleItem": { + "description": "캘린더 일정 아이템", + "properties": { + "id": { + "description": "일정 ID (타입_ID 형식)", + "type": "string", + "example": "wo_123" + }, + "title": { + "description": "일정 제목", + "type": "string", + "example": "스크린 생산" + }, + "startDate": { + "description": "시작일", + "type": "string", + "format": "date", + "example": "2026-01-20" + }, + "endDate": { + "description": "종료일", + "type": "string", + "format": "date", + "example": "2026-01-20" + }, + "startTime": { + "description": "시작 시간 (HH:mm)", + "type": "string", + "example": "09:00", + "nullable": true + }, + "endTime": { + "description": "종료 시간 (HH:mm)", + "type": "string", + "example": "18:00", + "nullable": true + }, + "isAllDay": { + "description": "종일 여부", + "type": "boolean", + "example": true + }, + "type": { + "description": "일정 타입 (schedule: 휴가/일반, order: 작업지시/발주, construction: 시공/계약)", + "type": "string", + "enum": [ + "schedule", + "order", + "construction", + "other" + ], + "example": "order" + }, + "department": { + "description": "부서명", + "type": "string", + "example": "생산팀", + "nullable": true + }, + "personName": { + "description": "담당자명", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "color": { + "description": "일정 색상", + "type": "string", + "example": "blue", + "nullable": true + } + }, + "type": "object" + }, + "CalendarScheduleSummary": { + "description": "캘린더 일정 요약 데이터", + "properties": { + "items": { + "description": "일정 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/CalendarScheduleItem" + } + }, + "total_count": { + "description": "총 일정 수", + "type": "integer", + "example": 15 + } + }, + "type": "object" + }, + "Card": { + "description": "카드 정보", + "properties": { + "id": { + "description": "카드 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "card_company": { + "description": "카드사", + "type": "string", + "example": "삼성카드" + }, + "card_number_last4": { + "description": "카드번호 끝 4자리", + "type": "string", + "example": "1234" + }, + "expiry_date": { + "description": "유효기간 (MM/YY)", + "type": "string", + "example": "12/25" + }, + "card_name": { + "description": "카드 별칭", + "type": "string", + "example": "법인카드 1" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "active" + }, + "assigned_user_id": { + "description": "담당자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "assigned_user": { + "description": "담당자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object", + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "description": "수정자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "CardCreateRequest": { + "description": "카드 등록 요청", + "required": [ + "card_company", + "card_number", + "expiry_date", + "card_name" + ], + "properties": { + "card_company": { + "description": "카드사", + "type": "string", + "maxLength": 50, + "example": "삼성카드" + }, + "card_number": { + "description": "카드번호 (13-19자리)", + "type": "string", + "example": "1234567890123456" + }, + "expiry_date": { + "description": "유효기간 (MM/YY)", + "type": "string", + "pattern": "^(0[1-9]|1[0-2])/\\\\d{2}$", + "example": "12/25" + }, + "card_password": { + "description": "비밀번호 앞 2자리 (선택)", + "type": "string", + "maxLength": 2, + "example": "12" + }, + "card_name": { + "description": "카드 별칭", + "type": "string", + "maxLength": 100, + "example": "법인카드 1" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "active" + }, + "assigned_user_id": { + "description": "담당자 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "CardUpdateRequest": { + "description": "카드 수정 요청", + "properties": { + "card_company": { + "description": "카드사", + "type": "string", + "maxLength": 50, + "example": "삼성카드" + }, + "card_number": { + "description": "카드번호 (변경 시)", + "type": "string", + "example": "1234567890123456" + }, + "expiry_date": { + "description": "유효기간 (MM/YY)", + "type": "string", + "pattern": "^(0[1-9]|1[0-2])/\\\\d{2}$", + "example": "12/25" + }, + "card_password": { + "description": "비밀번호 앞 2자리", + "type": "string", + "maxLength": 2, + "example": "12" + }, + "card_name": { + "description": "카드 별칭", + "type": "string", + "maxLength": 100, + "example": "법인카드 1" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "active" + }, + "assigned_user_id": { + "description": "담당자 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "CardListItem": { + "description": "카드 목록 아이템 (셀렉트박스용)", + "properties": { + "id": { + "description": "카드 ID", + "type": "integer", + "example": 1 + }, + "card_name": { + "description": "카드 별칭", + "type": "string", + "example": "법인카드 1" + }, + "card_company": { + "description": "카드사", + "type": "string", + "example": "삼성카드" + }, + "display_number": { + "description": "마스킹된 카드번호", + "type": "string", + "example": "****-1234" + } + }, + "type": "object" + }, + "CardTransactionItem": { + "description": "카드 거래 항목", + "properties": { + "id": { + "description": "거래 ID", + "type": "integer", + "example": 1 + }, + "card_id": { + "description": "카드 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "withdrawal_date": { + "description": "출금일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "used_at": { + "description": "사용일시", + "type": "string", + "format": "date-time", + "example": "2025-01-15T14:30:00Z", + "nullable": true + }, + "merchant_name": { + "description": "가맹점명", + "type": "string", + "example": "스타벅스 강남역점", + "nullable": true + }, + "amount": { + "description": "사용금액", + "type": "number", + "format": "float", + "example": 15000 + }, + "account_code": { + "description": "계정과목", + "type": "string", + "example": "expenses", + "nullable": true + }, + "description": { + "description": "적요", + "type": "string", + "example": "회의 다과", + "nullable": true + }, + "card": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "card_company": { + "type": "string", + "example": "신한" + }, + "card_number_last4": { + "type": "string", + "example": "1234" + }, + "card_name": { + "type": "string", + "example": "법인카드1" + }, + "assigned_user": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "description": "생성일시", + "type": "string", + "format": "date-time" + }, + "updated_at": { + "description": "수정일시", + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "CardTransactionSummary": { + "description": "카드 거래 요약 통계", + "properties": { + "previous_month_total": { + "description": "전월 사용액", + "type": "number", + "format": "float", + "example": 1500000 + }, + "current_month_total": { + "description": "당월 사용액", + "type": "number", + "format": "float", + "example": 850000 + }, + "total_count": { + "description": "조회 기간 내 거래 건수", + "type": "integer", + "example": 45 + }, + "total_amount": { + "description": "조회 기간 내 총 금액", + "type": "number", + "format": "float", + "example": 2350000 + } + }, + "type": "object" + }, + "CardTransactionPagination": { + "description": "카드 거래 목록 페이지네이션", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CardTransactionItem" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "last_page_url": { + "type": "string" + }, + "next_page_url": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer" + }, + "prev_page_url": { + "type": "string", + "nullable": true + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + }, + "type": "object" + }, + "CardTransactionBulkUpdateRequest": { + "description": "계정과목 일괄 수정 요청", + "required": [ + "ids", + "account_code" + ], + "properties": { + "ids": { + "description": "거래 ID 배열", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + }, + "account_code": { + "description": "계정과목 코드", + "type": "string", + "example": "expenses" + } + }, + "type": "object" + }, + "CardTransactionDashboard": { + "description": "카드 거래 대시보드 데이터 (CEO 대시보드 cm1 및 당월 예상 지출 me2 모달용)", + "properties": { + "summary": { + "description": "요약 통계", + "properties": { + "current_month_total": { + "description": "당월 카드 사용액", + "type": "number", + "format": "float", + "example": 30123000 + }, + "previous_month_total": { + "description": "전월 카드 사용액", + "type": "number", + "format": "float", + "example": 27250000 + }, + "change_rate": { + "description": "전월 대비 증감률 (%)", + "type": "number", + "format": "float", + "example": 10.5 + }, + "current_month_count": { + "description": "당월 이용 건수", + "type": "integer", + "example": 42 + }, + "unprocessed_count": { + "description": "미정리 건수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "monthly_trend": { + "description": "최근 6개월 추이", + "type": "array", + "items": { + "properties": { + "month": { + "description": "년월", + "type": "string", + "example": "2026-01" + }, + "amount": { + "description": "사용액", + "type": "number", + "format": "float", + "example": 25000000 + } + }, + "type": "object" + } + }, + "user_ratio": { + "description": "사용자별 비율", + "type": "array", + "items": { + "properties": { + "user_name": { + "description": "사용자명", + "type": "string", + "example": "홍길동" + }, + "amount": { + "description": "사용액", + "type": "number", + "format": "float", + "example": 15000000 + }, + "percentage": { + "description": "비율 (%)", + "type": "number", + "format": "float", + "example": 49.8 + } + }, + "type": "object" + } + }, + "recent_transactions": { + "description": "최근 거래 10건", + "type": "array", + "items": { + "properties": { + "id": { + "description": "거래 ID", + "type": "integer", + "example": 1 + }, + "card_name": { + "description": "카드명", + "type": "string", + "example": "법인카드1" + }, + "user_name": { + "description": "사용자명", + "type": "string", + "example": "홍길동" + }, + "used_at": { + "description": "사용일시", + "type": "string", + "example": "2026-01-15 14:30:00" + }, + "merchant_name": { + "description": "가맹점명", + "type": "string", + "example": "스타벅스 강남역점" + }, + "amount": { + "description": "사용금액", + "type": "number", + "format": "float", + "example": 15000 + }, + "usage_type": { + "description": "계정과목", + "type": "string", + "example": "expenses", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "Category": { + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 12 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "code": { + "type": "string", + "example": "ELC", + "nullable": true + }, + "name": { + "type": "string", + "example": "전자" + }, + "description": { + "type": "string", + "example": null, + "nullable": true + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "created_at": { + "type": "string", + "example": "2025-08-22 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-08-22 10:10:00" + } + }, + "type": "object" + }, + "CategoryPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Category" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/categories?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/categories?page=3" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/categories?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/categories" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 60 + } + }, + "type": "object" + }, + "CategoryCreateRequest": { + "required": [ + "name" + ], + "properties": { + "parent_id": { + "type": "integer", + "nullable": true + }, + "code": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "description": { + "type": "string", + "maxLength": 255, + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "sort_order": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "CategoryUpdateRequest": { + "properties": { + "parent_id": { + "type": "integer", + "nullable": true + }, + "code": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "description": { + "type": "string", + "maxLength": 255, + "nullable": true + }, + "is_active": { + "type": "boolean" + }, + "sort_order": { + "type": "integer" + } + }, + "type": "object" + }, + "CategoryTreeNode": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "code": { + "type": "string", + "example": "ELC", + "nullable": true + }, + "name": { + "type": "string", + "example": "전자" + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 0 + }, + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CategoryTreeNode" + } + } + }, + "type": "object" + }, + "CategoryField": { + "required": [ + "id", + "tenant_id", + "category_id", + "field_key", + "field_name", + "field_type" + ], + "properties": { + "id": { + "type": "integer", + "example": 11 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "category_id": { + "type": "integer", + "example": 7 + }, + "field_key": { + "type": "string", + "example": "width" + }, + "field_name": { + "type": "string", + "example": "폭(mm)" + }, + "field_type": { + "type": "string", + "example": "number" + }, + "is_required": { + "type": "boolean", + "example": false + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "default_value": { + "type": "string", + "example": null, + "nullable": true + }, + "options": { + "description": "선택지(콤보박스 등)", + "type": "object", + "example": { + "units": [ + "mm", + "cm", + "m" + ] + }, + "nullable": true + }, + "description": { + "type": "string", + "example": null, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 10:20:00" + } + }, + "type": "object" + }, + "CategoryFieldPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CategoryField" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + }, + "CategoryFieldCreateRequest": { + "required": [ + "field_key", + "field_name", + "field_type" + ], + "properties": { + "field_key": { + "type": "string", + "example": "height" + }, + "field_name": { + "type": "string", + "example": "높이(mm)" + }, + "field_type": { + "type": "string", + "example": "number" + }, + "is_required": { + "type": "string", + "enum": [ + "Y", + "N" + ], + "example": "N" + }, + "sort_order": { + "type": "integer", + "example": 2 + }, + "default_value": { + "type": "string", + "example": null, + "nullable": true + }, + "options": { + "type": "object", + "example": { + "min": 0, + "max": 9999, + "step": 1 + }, + "nullable": true + }, + "description": { + "type": "string", + "example": "선택 입력", + "nullable": true + } + }, + "type": "object" + }, + "CategoryFieldUpdateRequest": { + "properties": { + "field_key": { + "type": "string", + "example": "height" + }, + "field_name": { + "type": "string", + "example": "높이(mm)" + }, + "field_type": { + "type": "string", + "example": "number" + }, + "is_required": { + "type": "string", + "enum": [ + "Y", + "N" + ], + "example": "Y" + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "default_value": { + "type": "string", + "example": null, + "nullable": true + }, + "options": { + "type": "object", + "example": { + "min": 0, + "max": 9999, + "step": 1 + }, + "nullable": true + }, + "description": { + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "CategoryFieldReorderRequest": { + "type": "array", + "items": { + "required": [ + "id", + "sort_order" + ], + "properties": { + "id": { + "type": "integer", + "example": 11 + }, + "sort_order": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + }, + "CategoryFieldBulkUpsertRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": null, + "nullable": true + }, + "field_key": { + "type": "string", + "example": "thickness" + }, + "field_name": { + "type": "string", + "example": "두께(mm)" + }, + "field_type": { + "type": "string", + "example": "number" + }, + "is_required": { + "type": "string", + "enum": [ + "Y", + "N" + ], + "example": "N" + }, + "sort_order": { + "type": "integer", + "example": 3 + }, + "default_value": { + "type": "string", + "example": null, + "nullable": true + }, + "options": { + "type": "object", + "example": { + "unit": "mm" + }, + "nullable": true + }, + "description": { + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "CategoryTemplate": { + "required": [ + "id", + "tenant_id", + "category_id", + "version_no", + "template_json", + "applied_at" + ], + "properties": { + "id": { + "type": "integer", + "example": 1001 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "category_id": { + "type": "integer", + "example": 7 + }, + "version_no": { + "type": "integer", + "example": 3 + }, + "template_json": { + "description": "템플릿 스냅샷", + "type": "object", + "example": { + "fields": [ + { + "key": "width", + "type": "number", + "required": true + } + ] + } + }, + "applied_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 11:00:00" + }, + "remarks": { + "type": "string", + "example": "높이 필드 추가", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 10:50:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 11:05:00" + } + }, + "type": "object" + }, + "CategoryTemplateCreateRequest": { + "required": [ + "version_no", + "template_json", + "applied_at" + ], + "properties": { + "version_no": { + "type": "integer", + "example": 4 + }, + "template_json": { + "type": "object", + "example": { + "fields": [ + { + "key": "width", + "type": "number", + "required": true + }, + { + "key": "height", + "type": "number", + "required": false + } + ] + } + }, + "applied_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 13:00:00" + }, + "remarks": { + "type": "string", + "example": "높이 추가 버전", + "nullable": true + } + }, + "type": "object" + }, + "CategoryTemplateUpdateRequest": { + "properties": { + "template_json": { + "type": "object", + "example": { + "fields": [ + { + "key": "width", + "type": "number" + } + ] + } + }, + "applied_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-26 09:00:00" + }, + "remarks": { + "type": "string", + "example": "비고 수정", + "nullable": true + } + }, + "type": "object" + }, + "CategoryLog": { + "required": [ + "id", + "tenant_id", + "category_id", + "action", + "changed_at" + ], + "properties": { + "id": { + "type": "integer", + "example": 501 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "category_id": { + "type": "integer", + "example": 7 + }, + "action": { + "type": "string", + "example": "update" + }, + "changed_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "changed_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 14:00:00" + }, + "before_json": { + "type": "object", + "example": { + "name": "old" + }, + "nullable": true + }, + "after_json": { + "type": "object", + "example": { + "name": "new" + }, + "nullable": true + }, + "remarks": { + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "Classification": { + "required": [ + "id", + "group", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 11 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "group": { + "type": "string", + "example": "product_type" + }, + "code": { + "type": "string", + "example": "OUTER", + "nullable": true + }, + "name": { + "type": "string", + "example": "아우터" + }, + "description": { + "type": "string", + "example": null, + "nullable": true + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "created_at": { + "type": "string", + "example": "2025-08-22 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-08-22 10:10:00" + } + }, + "type": "object" + }, + "ClassificationPagination": { + "description": "라라벨 LengthAwarePaginator 기본 구조", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Classification" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/classifications?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/classifications?page=3" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/classifications?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/classifications" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 60 + } + }, + "type": "object" + }, + "ClassificationCreateRequest": { + "required": [ + "group", + "name" + ], + "properties": { + "group": { + "type": "string", + "maxLength": 50, + "example": "product_type" + }, + "code": { + "type": "string", + "maxLength": 50, + "example": "OUTER", + "nullable": true + }, + "name": { + "type": "string", + "maxLength": 100, + "example": "아우터" + }, + "description": { + "type": "string", + "maxLength": 255, + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "sort_order": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "ClassificationUpdateRequest": { + "properties": { + "group": { + "type": "string", + "maxLength": 50 + }, + "code": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "description": { + "type": "string", + "maxLength": 255, + "nullable": true + }, + "is_active": { + "type": "boolean" + }, + "sort_order": { + "type": "integer" + } + }, + "type": "object" + }, + "Client": { + "required": [ + "id", + "client_code", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "client_group_id": { + "description": "고객 그룹 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_code": { + "type": "string", + "example": "CLIENT_001" + }, + "name": { + "type": "string", + "example": "거래처명" + }, + "client_type": { + "description": "거래처 유형", + "type": "string", + "enum": [ + "매입", + "매출", + "매입매출" + ], + "example": "매입" + }, + "contact_person": { + "type": "string", + "example": "홍길동", + "nullable": true + }, + "phone": { + "type": "string", + "example": "02-1234-5678", + "nullable": true + }, + "mobile": { + "description": "모바일 번호", + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "fax": { + "description": "팩스 번호", + "type": "string", + "example": "02-1234-5679", + "nullable": true + }, + "email": { + "type": "string", + "example": "client@example.com", + "nullable": true + }, + "address": { + "type": "string", + "example": "서울시 강남구", + "nullable": true + }, + "manager_name": { + "description": "담당자명", + "type": "string", + "example": "김담당", + "nullable": true + }, + "manager_tel": { + "description": "담당자 전화", + "type": "string", + "example": "010-9876-5432", + "nullable": true + }, + "system_manager": { + "description": "시스템 관리자", + "type": "string", + "example": "박시스템", + "nullable": true + }, + "account_id": { + "description": "계정 ID", + "type": "string", + "example": "user123", + "nullable": true + }, + "purchase_payment_day": { + "description": "매입 결제일", + "type": "string", + "example": "매월 25일", + "nullable": true + }, + "sales_payment_day": { + "description": "매출 결제일", + "type": "string", + "example": "매월 말일", + "nullable": true + }, + "business_no": { + "description": "사업자등록번호", + "type": "string", + "maxLength": 20, + "example": "123-45-67890", + "nullable": true + }, + "business_type": { + "description": "업태", + "type": "string", + "maxLength": 50, + "example": "제조업", + "nullable": true + }, + "business_item": { + "description": "업종", + "type": "string", + "maxLength": 100, + "example": "전자부품", + "nullable": true + }, + "tax_agreement": { + "description": "세금 약정 여부", + "type": "boolean", + "example": false + }, + "tax_amount": { + "description": "약정 금액", + "type": "number", + "format": "float", + "example": 1000000, + "nullable": true + }, + "tax_start_date": { + "description": "약정 시작일", + "type": "string", + "format": "date", + "example": "2025-01-01", + "nullable": true + }, + "tax_end_date": { + "description": "약정 종료일", + "type": "string", + "format": "date", + "example": "2025-12-31", + "nullable": true + }, + "bad_debt": { + "description": "악성채권 여부", + "type": "boolean", + "example": false + }, + "bad_debt_amount": { + "description": "악성채권 금액", + "type": "number", + "format": "float", + "example": 500000, + "nullable": true + }, + "bad_debt_receive_date": { + "description": "채권 발생일", + "type": "string", + "format": "date", + "example": "2024-06-01", + "nullable": true + }, + "bad_debt_end_date": { + "description": "채권 만료일", + "type": "string", + "format": "date", + "example": "2025-06-01", + "nullable": true + }, + "bad_debt_progress": { + "description": "진행 상태", + "type": "string", + "enum": [ + "협의중", + "소송중", + "회수완료", + "대손처리" + ], + "nullable": true + }, + "memo": { + "description": "메모", + "type": "string", + "example": "특이사항 메모", + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "example": "2025-10-01 12:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-10-01 12:00:00" + } + }, + "type": "object" + }, + "ClientPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Client" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/clients?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/clients?page=3" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/clients?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/clients" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + }, + "ClientCreateRequest": { + "required": [ + "client_code", + "name" + ], + "properties": { + "client_group_id": { + "description": "고객 그룹 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_code": { + "type": "string", + "maxLength": 50, + "example": "CLIENT_001" + }, + "name": { + "type": "string", + "maxLength": 100, + "example": "거래처명" + }, + "client_type": { + "description": "거래처 유형", + "type": "string", + "enum": [ + "매입", + "매출", + "매입매출" + ], + "example": "매입", + "nullable": true + }, + "contact_person": { + "type": "string", + "maxLength": 100, + "example": "홍길동", + "nullable": true + }, + "phone": { + "type": "string", + "maxLength": 20, + "example": "02-1234-5678", + "nullable": true + }, + "mobile": { + "description": "모바일 번호", + "type": "string", + "maxLength": 20, + "example": "010-1234-5678", + "nullable": true + }, + "fax": { + "description": "팩스 번호", + "type": "string", + "maxLength": 20, + "example": "02-1234-5679", + "nullable": true + }, + "email": { + "type": "string", + "maxLength": 100, + "example": "client@example.com", + "nullable": true + }, + "address": { + "type": "string", + "maxLength": 255, + "example": "서울시 강남구", + "nullable": true + }, + "manager_name": { + "description": "담당자명", + "type": "string", + "maxLength": 50, + "example": "김담당", + "nullable": true + }, + "manager_tel": { + "description": "담당자 전화", + "type": "string", + "maxLength": 20, + "example": "010-9876-5432", + "nullable": true + }, + "system_manager": { + "description": "시스템 관리자", + "type": "string", + "maxLength": 50, + "example": "박시스템", + "nullable": true + }, + "account_id": { + "description": "계정 ID", + "type": "string", + "maxLength": 50, + "example": "user123", + "nullable": true + }, + "account_password": { + "description": "계정 비밀번호", + "type": "string", + "maxLength": 255, + "example": "password123", + "nullable": true + }, + "purchase_payment_day": { + "description": "매입 결제일", + "type": "string", + "maxLength": 20, + "example": "매월 25일", + "nullable": true + }, + "sales_payment_day": { + "description": "매출 결제일", + "type": "string", + "maxLength": 20, + "example": "매월 말일", + "nullable": true + }, + "business_no": { + "description": "사업자등록번호", + "type": "string", + "maxLength": 20, + "example": "123-45-67890", + "nullable": true + }, + "business_type": { + "description": "업태", + "type": "string", + "maxLength": 50, + "example": "제조업", + "nullable": true + }, + "business_item": { + "description": "업종", + "type": "string", + "maxLength": 100, + "example": "전자부품", + "nullable": true + }, + "tax_agreement": { + "description": "세금 약정 여부", + "type": "boolean", + "example": false, + "nullable": true + }, + "tax_amount": { + "description": "약정 금액", + "type": "number", + "format": "float", + "example": 1000000, + "nullable": true + }, + "tax_start_date": { + "description": "약정 시작일", + "type": "string", + "format": "date", + "example": "2025-01-01", + "nullable": true + }, + "tax_end_date": { + "description": "약정 종료일", + "type": "string", + "format": "date", + "example": "2025-12-31", + "nullable": true + }, + "bad_debt": { + "description": "악성채권 여부", + "type": "boolean", + "example": false, + "nullable": true + }, + "bad_debt_amount": { + "description": "악성채권 금액", + "type": "number", + "format": "float", + "example": 500000, + "nullable": true + }, + "bad_debt_receive_date": { + "description": "채권 발생일", + "type": "string", + "format": "date", + "example": "2024-06-01", + "nullable": true + }, + "bad_debt_end_date": { + "description": "채권 만료일", + "type": "string", + "format": "date", + "example": "2025-06-01", + "nullable": true + }, + "bad_debt_progress": { + "description": "진행 상태", + "type": "string", + "enum": [ + "협의중", + "소송중", + "회수완료", + "대손처리" + ], + "nullable": true + }, + "memo": { + "description": "메모", + "type": "string", + "example": "특이사항 메모", + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "ClientUpdateRequest": { + "properties": { + "client_group_id": { + "description": "고객 그룹 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_code": { + "type": "string", + "maxLength": 50 + }, + "name": { + "type": "string", + "maxLength": 100 + }, + "client_type": { + "description": "거래처 유형", + "type": "string", + "enum": [ + "매입", + "매출", + "매입매출" + ], + "nullable": true + }, + "contact_person": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "phone": { + "type": "string", + "maxLength": 20, + "nullable": true + }, + "mobile": { + "description": "모바일 번호", + "type": "string", + "maxLength": 20, + "nullable": true + }, + "fax": { + "description": "팩스 번호", + "type": "string", + "maxLength": 20, + "nullable": true + }, + "email": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "address": { + "type": "string", + "maxLength": 255, + "nullable": true + }, + "manager_name": { + "description": "담당자명", + "type": "string", + "maxLength": 50, + "nullable": true + }, + "manager_tel": { + "description": "담당자 전화", + "type": "string", + "maxLength": 20, + "nullable": true + }, + "system_manager": { + "description": "시스템 관리자", + "type": "string", + "maxLength": 50, + "nullable": true + }, + "account_id": { + "description": "계정 ID", + "type": "string", + "maxLength": 50, + "nullable": true + }, + "account_password": { + "description": "계정 비밀번호", + "type": "string", + "maxLength": 255, + "nullable": true + }, + "purchase_payment_day": { + "description": "매입 결제일", + "type": "string", + "maxLength": 20, + "nullable": true + }, + "sales_payment_day": { + "description": "매출 결제일", + "type": "string", + "maxLength": 20, + "nullable": true + }, + "business_no": { + "description": "사업자등록번호", + "type": "string", + "maxLength": 20, + "nullable": true + }, + "business_type": { + "description": "업태", + "type": "string", + "maxLength": 50, + "nullable": true + }, + "business_item": { + "description": "업종", + "type": "string", + "maxLength": 100, + "nullable": true + }, + "tax_agreement": { + "description": "세금 약정 여부", + "type": "boolean", + "nullable": true + }, + "tax_amount": { + "description": "약정 금액", + "type": "number", + "format": "float", + "nullable": true + }, + "tax_start_date": { + "description": "약정 시작일", + "type": "string", + "format": "date", + "nullable": true + }, + "tax_end_date": { + "description": "약정 종료일", + "type": "string", + "format": "date", + "nullable": true + }, + "bad_debt": { + "description": "악성채권 여부", + "type": "boolean", + "nullable": true + }, + "bad_debt_amount": { + "description": "악성채권 금액", + "type": "number", + "format": "float", + "nullable": true + }, + "bad_debt_receive_date": { + "description": "채권 발생일", + "type": "string", + "format": "date", + "nullable": true + }, + "bad_debt_end_date": { + "description": "채권 만료일", + "type": "string", + "format": "date", + "nullable": true + }, + "bad_debt_progress": { + "description": "진행 상태", + "type": "string", + "enum": [ + "협의중", + "소송중", + "회수완료", + "대손처리" + ], + "nullable": true + }, + "memo": { + "description": "메모", + "type": "string", + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean" + } + }, + "type": "object" + }, + "ClientGroup": { + "required": [ + "id", + "group_code", + "group_name", + "price_rate" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "group_code": { + "type": "string", + "example": "VIP" + }, + "group_name": { + "type": "string", + "example": "VIP 고객" + }, + "price_rate": { + "description": "가격 배율 (1.0=기준가, 0.9=90%, 1.1=110%)", + "type": "number", + "format": "decimal", + "example": 0.9 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "example": "2025-10-01 12:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-10-01 12:00:00" + } + }, + "type": "object" + }, + "ClientGroupPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClientGroup" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/client-groups?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/client-groups?page=3" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/client-groups?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/client-groups" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + }, + "ClientGroupCreateRequest": { + "required": [ + "group_code", + "group_name", + "price_rate" + ], + "properties": { + "group_code": { + "description": "그룹 코드", + "type": "string", + "maxLength": 30, + "example": "VIP" + }, + "group_name": { + "description": "그룹명", + "type": "string", + "maxLength": 100, + "example": "VIP 고객" + }, + "price_rate": { + "description": "가격 배율 (1.0=기준가)", + "type": "number", + "format": "decimal", + "example": 0.9 + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "ClientGroupUpdateRequest": { + "properties": { + "group_code": { + "type": "string", + "maxLength": 30 + }, + "group_name": { + "type": "string", + "maxLength": 100 + }, + "price_rate": { + "type": "number", + "format": "decimal" + }, + "is_active": { + "type": "boolean" + } + }, + "type": "object" + }, + "CommonCode": { + "properties": { + "id": { + "type": "integer" + }, + "code_group": { + "type": "string", + "example": "product_type" + }, + "code": { + "type": "string", + "example": "PRODUCT" + }, + "name": { + "type": "string", + "example": "제품" + }, + "description": { + "type": "string", + "example": "완제품" + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "CommonCodeCreateRequest": { + "required": [ + "code_group", + "code", + "name" + ], + "properties": { + "code_group": { + "type": "string", + "example": "product_type" + }, + "code": { + "type": "string", + "example": "SERVICE" + }, + "name": { + "type": "string", + "example": "서비스" + }, + "description": { + "type": "string", + "example": "서비스 상품" + } + }, + "type": "object" + }, + "CommonCodeUpdateRequest": { + "properties": { + "name": { + "type": "string", + "example": "수정된 이름" + }, + "description": { + "type": "string", + "example": "수정된 설명" + } + }, + "type": "object" + }, + "ApiResponse": { + "properties": { + "success": { + "description": "전역 재사용 컴포넌트 정의만 모아둔 파일입니다.", + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "요청 성공" + }, + "data": { + "nullable": true + } + }, + "type": "object" + }, + "PaginationMeta": { + "properties": { + "page": { + "type": "integer", + "example": 1 + }, + "size": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 126 + }, + "last_page": { + "type": "integer", + "example": 7 + } + }, + "type": "object" + }, + "User": { + "required": [ + "id", + "name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "example": 101 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hong@kdcorp.co.kr" + }, + "phone": { + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "admin", + "manager" + ] + }, + "created_at": { + "type": "string", + "example": "2025-07-20 10:22:33" + }, + "updated_at": { + "type": "string", + "example": "2025-08-01 15:00:10" + } + }, + "type": "object" + }, + "LoginRequest": { + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string", + "example": "hong@kdcorp.co.kr" + }, + "password": { + "type": "string", + "example": "secret1234!" + } + }, + "type": "object" + }, + "TokenResponse": { + "properties": { + "access_token": { + "type": "string", + "example": "eyJhbGciOi..." + }, + "token_type": { + "type": "string", + "example": "Bearer" + }, + "expires_in": { + "type": "integer", + "example": 3600 + } + }, + "type": "object" + }, + "ErrorResponse": { + "description": "공통 에러 응답 포맷", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "요청 실패" + }, + "error": { + "properties": { + "code": { + "type": "integer", + "example": 400 + }, + "details": { + "example": null, + "nullable": true + } + }, + "type": "object" + } + }, + "type": "object" + }, + "CompanyRequest": { + "description": "회사 추가 신청 정보", + "properties": { + "id": { + "description": "신청 ID", + "type": "integer", + "example": 1 + }, + "user_id": { + "description": "신청자 ID", + "type": "integer", + "example": 1 + }, + "business_number": { + "description": "사업자등록번호", + "type": "string", + "example": "1234567890" + }, + "formatted_business_number": { + "description": "사업자등록번호 (포맷)", + "type": "string", + "example": "123-45-67890" + }, + "company_name": { + "description": "회사명", + "type": "string", + "example": "주식회사 테스트" + }, + "ceo_name": { + "description": "대표자명", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "address": { + "description": "주소", + "type": "string", + "example": "서울시 강남구 테헤란로 123", + "nullable": true + }, + "phone": { + "description": "전화번호", + "type": "string", + "example": "02-1234-5678", + "nullable": true + }, + "email": { + "description": "이메일", + "type": "string", + "example": "contact@test.com", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "pending", + "approved", + "rejected" + ], + "example": "pending" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "대기중" + }, + "message": { + "description": "신청 메시지", + "type": "string", + "nullable": true + }, + "reject_reason": { + "description": "반려 사유", + "type": "string", + "nullable": true + }, + "barobill_response": { + "description": "바로빌 검증 응답", + "type": "object", + "nullable": true + }, + "approved_by": { + "description": "승인/반려 처리자 ID", + "type": "integer", + "nullable": true + }, + "created_tenant_id": { + "description": "생성된 테넌트 ID", + "type": "integer", + "nullable": true + }, + "processed_at": { + "description": "처리일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "is_pending": { + "description": "대기중 여부", + "type": "boolean", + "example": true + }, + "is_approved": { + "description": "승인됨 여부", + "type": "boolean", + "example": false + }, + "is_rejected": { + "description": "반려됨 여부", + "type": "boolean", + "example": false + }, + "user": { + "description": "신청자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "user@example.com" + } + }, + "type": "object", + "nullable": true + }, + "approver": { + "description": "처리자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "관리자" + }, + "email": { + "type": "string", + "example": "admin@example.com" + } + }, + "type": "object", + "nullable": true + }, + "created_tenant": { + "description": "생성된 테넌트 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "company_name": { + "type": "string", + "example": "주식회사 테스트" + }, + "code": { + "type": "string", + "example": "TEST0001" + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "BusinessNumberCheckResponse": { + "description": "사업자등록번호 검증 결과", + "properties": { + "valid": { + "description": "유효 여부", + "type": "boolean", + "example": true + }, + "status": { + "description": "상태 코드", + "type": "string", + "example": "01" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "사업중" + }, + "corp_name": { + "description": "회사명 (바로빌 조회)", + "type": "string", + "example": "주식회사 테스트", + "nullable": true + }, + "ceo_name": { + "description": "대표자명 (바로빌 조회)", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "message": { + "description": "결과 메시지", + "type": "string", + "example": "유효한 사업자등록번호입니다." + }, + "already_exists": { + "description": "이미 등록된 회사 여부", + "type": "boolean", + "example": false + }, + "existing_company_name": { + "description": "이미 등록된 회사명", + "type": "string", + "nullable": true + } + }, + "type": "object" + }, + "CompanyRequestCreateRequest": { + "description": "회사 추가 신청 요청", + "required": [ + "business_number", + "company_name" + ], + "properties": { + "business_number": { + "description": "사업자등록번호 (하이픈 포함/미포함 모두 가능)", + "type": "string", + "maxLength": 13, + "minLength": 10, + "example": "1234567890" + }, + "company_name": { + "description": "회사명", + "type": "string", + "maxLength": 200, + "example": "주식회사 테스트" + }, + "ceo_name": { + "description": "대표자명", + "type": "string", + "maxLength": 50, + "example": "홍길동", + "nullable": true + }, + "address": { + "description": "주소", + "type": "string", + "maxLength": 300, + "example": "서울시 강남구 테헤란로 123", + "nullable": true + }, + "phone": { + "description": "전화번호", + "type": "string", + "maxLength": 30, + "example": "02-1234-5678", + "nullable": true + }, + "email": { + "description": "이메일", + "type": "string", + "format": "email", + "maxLength": 100, + "example": "contact@test.com", + "nullable": true + }, + "message": { + "description": "신청 메시지", + "type": "string", + "maxLength": 1000, + "example": "신규 법인 등록 요청드립니다.", + "nullable": true + } + }, + "type": "object" + }, + "CompanyRequestActionRequest": { + "description": "회사 추가 신청 처리 요청", + "properties": { + "reason": { + "description": "처리 사유 (반려 시 필수)", + "type": "string", + "maxLength": 500, + "example": "서류 미비로 반려합니다.", + "nullable": true + } + }, + "type": "object" + }, + "CompanyRequestPagination": { + "description": "회사 추가 신청 목록 (페이지네이션)", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompanyRequest" + } + }, + "links": { + "properties": { + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string", + "nullable": true + }, + "next": { + "type": "string", + "nullable": true + } + }, + "type": "object" + }, + "meta": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 1 + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "to": { + "type": "integer", + "example": 5 + }, + "total": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "CheckPoint": { + "description": "체크포인트 아이템", + "properties": { + "id": { + "description": "ID", + "type": "string", + "example": "expense-cp-1" + }, + "type": { + "description": "타입", + "type": "string", + "enum": [ + "success", + "warning", + "error", + "info" + ], + "example": "warning" + }, + "message": { + "description": "메시지", + "type": "string", + "example": "연체 중인 지출이 있습니다." + }, + "highlight": { + "description": "강조 텍스트", + "type": "string", + "example": "1,000,000원", + "nullable": true + } + }, + "type": "object" + }, + "AmountCard": { + "description": "금액 카드 아이템", + "properties": { + "id": { + "description": "ID", + "type": "string", + "example": "expense-1" + }, + "label": { + "description": "라벨", + "type": "string", + "example": "이번 달 예상 지출" + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "sub_amount": { + "description": "부가 금액", + "type": "number", + "format": "float", + "nullable": true + }, + "sub_label": { + "description": "부가 라벨", + "type": "string", + "nullable": true + }, + "previous_amount": { + "description": "이전 금액", + "type": "number", + "format": "float", + "nullable": true + }, + "previous_label": { + "description": "이전 라벨", + "type": "string", + "nullable": true + } + }, + "type": "object" + }, + "ComprehensiveTodayIssueItem": { + "description": "종합분석 오늘의 이슈 아이템", + "properties": { + "id": { + "description": "ID", + "type": "string", + "example": "issue-1" + }, + "category": { + "description": "카테고리", + "type": "string", + "example": "결재요청" + }, + "description": { + "description": "설명", + "type": "string", + "example": "매입 처리 결재 요청" + }, + "requires_approval": { + "description": "승인 필요 여부", + "type": "boolean", + "example": true + }, + "time": { + "description": "시간", + "type": "string", + "example": "09:30" + } + }, + "type": "object" + }, + "TodayIssueSection": { + "description": "오늘의 이슈 섹션", + "properties": { + "filter_options": { + "description": "필터 옵션", + "type": "array", + "items": { + "type": "string" + } + }, + "items": { + "description": "이슈 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/ComprehensiveTodayIssueItem" + } + } + }, + "type": "object" + }, + "ExpenseSection": { + "description": "지출 섹션 공통 스키마", + "properties": { + "cards": { + "description": "금액 카드 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/AmountCard" + } + }, + "check_points": { + "description": "체크포인트 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/CheckPoint" + } + } + }, + "type": "object" + }, + "ReceivableSection": { + "description": "미수금 현황 섹션", + "properties": { + "cards": { + "description": "금액 카드 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/AmountCard" + } + }, + "check_points": { + "description": "체크포인트 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/CheckPoint" + } + }, + "has_detail_button": { + "description": "상세 버튼 표시 여부", + "type": "boolean", + "example": true + }, + "detail_button_label": { + "description": "상세 버튼 라벨", + "type": "string", + "example": "거래처별 미수금 현황" + }, + "detail_button_path": { + "description": "상세 페이지 경로", + "type": "string", + "example": "/accounting/receivables-status" + } + }, + "type": "object" + }, + "ComprehensiveAnalysisData": { + "description": "종합 분석 데이터", + "properties": { + "today_issue": { + "$ref": "#/components/schemas/TodayIssueSection" + }, + "monthly_expense": { + "$ref": "#/components/schemas/ExpenseSection" + }, + "card_management": { + "$ref": "#/components/schemas/ExpenseSection" + }, + "entertainment": { + "$ref": "#/components/schemas/ExpenseSection" + }, + "welfare": { + "$ref": "#/components/schemas/ExpenseSection" + }, + "receivable": { + "$ref": "#/components/schemas/ReceivableSection" + }, + "debt_collection": { + "$ref": "#/components/schemas/ExpenseSection" + } + }, + "type": "object" + }, + "Contract": { + "required": [ + "id", + "contract_code", + "project_name" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "contract_code": { + "description": "계약번호", + "type": "string", + "maxLength": 50, + "example": "CT-2026-001" + }, + "project_name": { + "description": "현장명", + "type": "string", + "maxLength": 255, + "example": "서울 A타워 시공" + }, + "partner_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "partner_name": { + "description": "거래처명", + "type": "string", + "maxLength": 255, + "example": "ABC건설", + "nullable": true + }, + "contract_manager_id": { + "description": "계약담당자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "contract_manager_name": { + "description": "계약담당자명", + "type": "string", + "maxLength": 100, + "example": "홍길동", + "nullable": true + }, + "construction_pm_id": { + "description": "공사PM ID", + "type": "integer", + "example": 2, + "nullable": true + }, + "construction_pm_name": { + "description": "공사PM명", + "type": "string", + "maxLength": 100, + "example": "김철수", + "nullable": true + }, + "total_locations": { + "description": "총 개소수", + "type": "integer", + "example": 15 + }, + "contract_amount": { + "description": "계약금액", + "type": "number", + "format": "float", + "example": 150000000 + }, + "contract_start_date": { + "description": "계약시작일", + "type": "string", + "format": "date", + "example": "2026-01-01", + "nullable": true + }, + "contract_end_date": { + "description": "계약종료일", + "type": "string", + "format": "date", + "example": "2026-12-31", + "nullable": true + }, + "status": { + "description": "상태 (pending: 계약대기, completed: 계약완료)", + "type": "string", + "enum": [ + "pending", + "completed" + ], + "example": "pending" + }, + "stage": { + "description": "단계 (estimate_selected: 견적선정, estimate_progress: 견적진행, delivery: 납품, installation: 설치중, inspection: 검수, other: 기타)", + "type": "string", + "enum": [ + "estimate_selected", + "estimate_progress", + "delivery", + "installation", + "inspection", + "other" + ], + "example": "estimate_selected" + }, + "bidding_id": { + "description": "입찰 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "bidding_code": { + "description": "입찰번호", + "type": "string", + "maxLength": 50, + "example": "BID-2025-001", + "nullable": true + }, + "remarks": { + "description": "비고", + "type": "string", + "example": "특이사항 없음", + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + }, + "created_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "example": "2026-01-08 12:00:00" + }, + "updated_at": { + "type": "string", + "example": "2026-01-08 12:00:00" + } + }, + "type": "object" + }, + "ContractPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Contract" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/construction/contracts?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/construction/contracts?page=3" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/construction/contracts?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/construction/contracts" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + }, + "ContractCreateRequest": { + "required": [ + "contract_code", + "project_name" + ], + "properties": { + "contract_code": { + "description": "계약번호", + "type": "string", + "maxLength": 50, + "example": "CT-2026-001" + }, + "project_name": { + "description": "현장명", + "type": "string", + "maxLength": 255, + "example": "서울 A타워 시공" + }, + "partner_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "partner_name": { + "description": "거래처명", + "type": "string", + "maxLength": 255, + "example": "ABC건설", + "nullable": true + }, + "contract_manager_id": { + "description": "계약담당자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "contract_manager_name": { + "description": "계약담당자명", + "type": "string", + "maxLength": 100, + "example": "홍길동", + "nullable": true + }, + "construction_pm_id": { + "description": "공사PM ID", + "type": "integer", + "example": 2, + "nullable": true + }, + "construction_pm_name": { + "description": "공사PM명", + "type": "string", + "maxLength": 100, + "example": "김철수", + "nullable": true + }, + "total_locations": { + "description": "총 개소수", + "type": "integer", + "example": 15, + "nullable": true + }, + "contract_amount": { + "description": "계약금액", + "type": "number", + "format": "float", + "example": 150000000, + "nullable": true + }, + "contract_start_date": { + "description": "계약시작일", + "type": "string", + "format": "date", + "example": "2026-01-01", + "nullable": true + }, + "contract_end_date": { + "description": "계약종료일", + "type": "string", + "format": "date", + "example": "2026-12-31", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "pending", + "completed" + ], + "example": "pending", + "nullable": true + }, + "stage": { + "description": "단계", + "type": "string", + "enum": [ + "estimate_selected", + "estimate_progress", + "delivery", + "installation", + "inspection", + "other" + ], + "example": "estimate_selected", + "nullable": true + }, + "bidding_id": { + "description": "입찰 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "bidding_code": { + "description": "입찰번호", + "type": "string", + "maxLength": 50, + "example": "BID-2025-001", + "nullable": true + }, + "remarks": { + "description": "비고", + "type": "string", + "example": "특이사항 없음", + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true, + "nullable": true + } + }, + "type": "object" + }, + "ContractUpdateRequest": { + "properties": { + "contract_code": { + "description": "계약번호", + "type": "string", + "maxLength": 50 + }, + "project_name": { + "description": "현장명", + "type": "string", + "maxLength": 255 + }, + "partner_id": { + "description": "거래처 ID", + "type": "integer", + "nullable": true + }, + "partner_name": { + "description": "거래처명", + "type": "string", + "maxLength": 255, + "nullable": true + }, + "contract_manager_id": { + "description": "계약담당자 ID", + "type": "integer", + "nullable": true + }, + "contract_manager_name": { + "description": "계약담당자명", + "type": "string", + "maxLength": 100, + "nullable": true + }, + "construction_pm_id": { + "description": "공사PM ID", + "type": "integer", + "nullable": true + }, + "construction_pm_name": { + "description": "공사PM명", + "type": "string", + "maxLength": 100, + "nullable": true + }, + "total_locations": { + "description": "총 개소수", + "type": "integer", + "nullable": true + }, + "contract_amount": { + "description": "계약금액", + "type": "number", + "format": "float", + "nullable": true + }, + "contract_start_date": { + "description": "계약시작일", + "type": "string", + "format": "date", + "nullable": true + }, + "contract_end_date": { + "description": "계약종료일", + "type": "string", + "format": "date", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "pending", + "completed" + ], + "nullable": true + }, + "stage": { + "description": "단계", + "type": "string", + "enum": [ + "estimate_selected", + "estimate_progress", + "delivery", + "installation", + "inspection", + "other" + ], + "nullable": true + }, + "bidding_id": { + "description": "입찰 ID", + "type": "integer", + "nullable": true + }, + "bidding_code": { + "description": "입찰번호", + "type": "string", + "maxLength": 50, + "nullable": true + }, + "remarks": { + "description": "비고", + "type": "string", + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "nullable": true + } + }, + "type": "object" + }, + "ContractStats": { + "properties": { + "total_count": { + "description": "전체 계약 수", + "type": "integer", + "example": 50 + }, + "pending_count": { + "description": "계약대기 수", + "type": "integer", + "example": 30 + }, + "completed_count": { + "description": "계약완료 수", + "type": "integer", + "example": 20 + }, + "total_amount": { + "description": "총 계약금액", + "type": "number", + "format": "float", + "example": 5000000000 + }, + "total_locations": { + "description": "총 개소수", + "type": "integer", + "example": 500 + } + }, + "type": "object" + }, + "ContractStageCounts": { + "properties": { + "estimate_selected": { + "description": "견적선정 수", + "type": "integer", + "example": 10 + }, + "estimate_progress": { + "description": "견적진행 수", + "type": "integer", + "example": 15 + }, + "delivery": { + "description": "납품 수", + "type": "integer", + "example": 8 + }, + "installation": { + "description": "설치중 수", + "type": "integer", + "example": 12 + }, + "inspection": { + "description": "검수 수", + "type": "integer", + "example": 3 + }, + "other": { + "description": "기타 수", + "type": "integer", + "example": 2 + } + }, + "type": "object" + }, + "ContractFromBiddingRequest": { + "description": "입찰에서 계약 생성 요청 (모든 필드 선택, 입찰 데이터에서 자동 매핑)", + "properties": { + "project_name": { + "description": "현장명 (미입력시 입찰 데이터 사용)", + "type": "string", + "maxLength": 255 + }, + "partner_id": { + "description": "거래처 ID (미입력시 입찰 거래처 사용)", + "type": "integer", + "nullable": true + }, + "partner_name": { + "description": "거래처명 (미입력시 입찰 거래처명 사용)", + "type": "string", + "maxLength": 255, + "nullable": true + }, + "contract_manager_id": { + "description": "계약담당자 ID", + "type": "integer", + "nullable": true + }, + "contract_manager_name": { + "description": "계약담당자명", + "type": "string", + "maxLength": 100, + "nullable": true + }, + "construction_pm_id": { + "description": "공사PM ID", + "type": "integer", + "nullable": true + }, + "construction_pm_name": { + "description": "공사PM명", + "type": "string", + "maxLength": 100, + "nullable": true + }, + "total_locations": { + "description": "총 개소수 (미입력시 입찰 총수량 사용)", + "type": "integer", + "nullable": true + }, + "contract_amount": { + "description": "계약금액 (미입력시 입찰금액 사용)", + "type": "number", + "format": "float", + "nullable": true + }, + "contract_start_date": { + "description": "계약시작일 (미입력시 입찰 공사시작일 사용)", + "type": "string", + "format": "date", + "nullable": true + }, + "contract_end_date": { + "description": "계약종료일 (미입력시 입찰 공사종료일 사용)", + "type": "string", + "format": "date", + "nullable": true + }, + "status": { + "description": "상태 (기본: pending)", + "type": "string", + "enum": [ + "pending", + "completed" + ], + "example": "pending", + "nullable": true + }, + "stage": { + "description": "단계 (기본: estimate_selected)", + "type": "string", + "enum": [ + "estimate_selected", + "estimate_progress", + "delivery", + "installation", + "inspection", + "other" + ], + "example": "estimate_selected", + "nullable": true + }, + "remarks": { + "description": "비고 (미입력시 입찰 비고 사용)", + "type": "string", + "nullable": true + }, + "is_active": { + "description": "활성 여부 (기본: true)", + "type": "boolean", + "example": true, + "nullable": true + } + }, + "type": "object" + }, + "NoteReceivableItem": { + "description": "어음 및 외상매출채권 아이템", + "properties": { + "id": { + "description": "ID", + "type": "string", + "example": "1" + }, + "content": { + "description": "내용", + "type": "string", + "example": "(수취어음) 거래처명 - 12312123" + }, + "current_balance": { + "description": "현재 잔액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "issue_date": { + "description": "발행일", + "type": "string", + "format": "date", + "example": "2025-12-12" + }, + "due_date": { + "description": "만기일", + "type": "string", + "format": "date", + "example": "2025-12-13" + } + }, + "type": "object" + }, + "DailyAccountItem": { + "description": "일별 계좌 현황 아이템", + "properties": { + "id": { + "description": "계좌 ID", + "type": "string", + "example": "1" + }, + "category": { + "description": "구분 (은행명 계좌번호)", + "type": "string", + "example": "국민 ****3121" + }, + "match_status": { + "description": "매칭 상태", + "type": "string", + "enum": [ + "matched", + "unmatched" + ], + "example": "matched" + }, + "carryover": { + "description": "전월 이월", + "type": "number", + "format": "float", + "example": 1000000 + }, + "income": { + "description": "수입", + "type": "number", + "format": "float", + "example": 500000 + }, + "expense": { + "description": "지출", + "type": "number", + "format": "float", + "example": 300000 + }, + "balance": { + "description": "잔액", + "type": "number", + "format": "float", + "example": 1200000 + }, + "currency": { + "description": "통화", + "type": "string", + "enum": [ + "KRW", + "USD" + ], + "example": "KRW" + } + }, + "type": "object" + }, + "DailyReportSummary": { + "description": "일일 보고서 요약", + "properties": { + "date": { + "description": "조회 일자", + "type": "string", + "format": "date", + "example": "2025-12-26" + }, + "day_of_week": { + "description": "요일", + "type": "string", + "example": "목요일" + }, + "note_receivable_total": { + "description": "어음 합계", + "type": "number", + "format": "float", + "example": 5000000 + }, + "foreign_currency_total": { + "description": "외화 합계 (USD)", + "type": "number", + "format": "float", + "example": 0 + }, + "cash_asset_total": { + "description": "현금성 자산 합계", + "type": "number", + "format": "float", + "example": 10000000 + }, + "krw_totals": { + "description": "KRW 합계", + "properties": { + "carryover": { + "type": "number", + "format": "float" + }, + "income": { + "type": "number", + "format": "float" + }, + "expense": { + "type": "number", + "format": "float" + }, + "balance": { + "type": "number", + "format": "float" + } + }, + "type": "object" + }, + "usd_totals": { + "description": "USD 합계", + "properties": { + "carryover": { + "type": "number", + "format": "float" + }, + "income": { + "type": "number", + "format": "float" + }, + "expense": { + "type": "number", + "format": "float" + }, + "balance": { + "type": "number", + "format": "float" + } + }, + "type": "object" + }, + "monthly_operating_expense": { + "description": "월 운영비 (직전 3개월 평균)", + "type": "number", + "format": "float", + "example": 500000000 + }, + "operating_months": { + "description": "운영 가능 개월 수 (현금자산/월운영비)", + "type": "number", + "format": "float", + "example": 6.5, + "nullable": true + }, + "operating_stability": { + "description": "운영자금 안정성 (stable: 6개월↑, caution: 3~6개월, warning: 3개월↓)", + "type": "string", + "enum": [ + "stable", + "caution", + "warning", + "unknown" + ], + "example": "stable" + } + }, + "type": "object" + }, + "DashboardSummary": { + "description": "대시보드 요약 데이터", + "properties": { + "today": { + "description": "오늘 요약", + "properties": { + "date": { + "description": "오늘 날짜", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "attendances_count": { + "description": "오늘 출근자 수", + "type": "integer", + "example": 25 + }, + "leaves_count": { + "description": "오늘 휴가자 수", + "type": "integer", + "example": 3 + }, + "approvals_pending": { + "description": "결재 대기 문서 수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "finance": { + "description": "재무 요약", + "properties": { + "monthly_deposit": { + "description": "월간 입금액", + "type": "number", + "format": "float", + "example": 50000000 + }, + "monthly_withdrawal": { + "description": "월간 출금액", + "type": "number", + "format": "float", + "example": 30000000 + }, + "balance": { + "description": "현재 잔액", + "type": "number", + "format": "float", + "example": 150000000 + } + }, + "type": "object" + }, + "sales": { + "description": "매출/매입 요약", + "properties": { + "monthly_sales": { + "description": "월간 매출", + "type": "number", + "format": "float", + "example": 80000000 + }, + "monthly_purchases": { + "description": "월간 매입", + "type": "number", + "format": "float", + "example": 45000000 + } + }, + "type": "object" + }, + "tasks": { + "description": "할 일 요약", + "properties": { + "pending_approvals": { + "description": "내가 결재할 문서 수", + "type": "integer", + "example": 3 + }, + "pending_leaves": { + "description": "승인 대기 휴가 신청 수", + "type": "integer", + "example": 2 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "DashboardCharts": { + "description": "대시보드 차트 데이터", + "properties": { + "period": { + "description": "조회 기간", + "type": "string", + "enum": [ + "week", + "month", + "quarter" + ], + "example": "month" + }, + "start_date": { + "description": "시작일", + "type": "string", + "format": "date", + "example": "2024-12-17" + }, + "end_date": { + "description": "종료일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "deposit_trend": { + "description": "입금 추이", + "type": "array", + "items": { + "properties": { + "date": { + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "amount": { + "type": "number", + "format": "float", + "example": 5000000 + } + }, + "type": "object" + } + }, + "withdrawal_trend": { + "description": "출금 추이", + "type": "array", + "items": { + "properties": { + "date": { + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "amount": { + "type": "number", + "format": "float", + "example": 3000000 + } + }, + "type": "object" + } + }, + "sales_by_client": { + "description": "거래처별 매출 (상위 10개)", + "type": "array", + "items": { + "properties": { + "client_id": { + "type": "integer", + "example": 1 + }, + "client_name": { + "type": "string", + "example": "(주)테스트" + }, + "amount": { + "type": "number", + "format": "float", + "example": 15000000 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "DashboardApprovals": { + "description": "대시보드 결재 현황", + "properties": { + "pending_approvals": { + "description": "결재 대기 문서 (내가 결재할 문서)", + "type": "array", + "items": { + "properties": { + "id": { + "description": "결재문서 ID", + "type": "integer", + "example": 1 + }, + "title": { + "description": "제목", + "type": "string", + "example": "출장 신청서" + }, + "drafter_name": { + "description": "기안자명", + "type": "string", + "example": "홍길동" + }, + "status": { + "description": "상태", + "type": "string", + "example": "pending" + }, + "created_at": { + "description": "생성일시", + "type": "string", + "format": "date-time", + "example": "2025-01-15 10:30:00" + } + }, + "type": "object" + } + }, + "my_drafts": { + "description": "내가 기안한 진행중인 문서", + "type": "array", + "items": { + "properties": { + "id": { + "description": "결재문서 ID", + "type": "integer", + "example": 2 + }, + "title": { + "description": "제목", + "type": "string", + "example": "휴가 신청서" + }, + "status": { + "description": "상태", + "type": "string", + "example": "pending" + }, + "current_step": { + "description": "현재 결재 단계", + "type": "integer", + "example": 2 + }, + "created_at": { + "description": "생성일시", + "type": "string", + "format": "date-time", + "example": "2025-01-14 09:00:00" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "Department": { + "description": "부서 상세", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 7 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "code": { + "type": "string", + "example": "OPS", + "nullable": true + }, + "name": { + "type": "string", + "example": "운영팀" + }, + "description": { + "type": "string", + "example": "서비스 운영 총괄", + "nullable": true + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-16 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-16 10:00:00" + } + }, + "type": "object" + }, + "DepartmentBrief": { + "description": "부서 요약", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 7 + }, + "code": { + "type": "string", + "example": "OPS", + "nullable": true + }, + "name": { + "type": "string", + "example": "운영팀" + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + }, + "DepartmentList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DepartmentBrief" + } + }, + "DepartmentCreateRequest": { + "required": [ + "name" + ], + "properties": { + "code": { + "type": "string", + "example": "OPS", + "nullable": true + }, + "name": { + "type": "string", + "example": "운영팀" + }, + "description": { + "type": "string", + "example": "서비스 운영 총괄", + "nullable": true + }, + "is_active": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "DepartmentUpdateRequest": { + "properties": { + "code": { + "type": "string", + "example": "OPS2", + "nullable": true + }, + "name": { + "type": "string", + "example": "운영기획팀" + }, + "description": { + "type": "string", + "example": "운영 기획/성과 관리", + "nullable": true + }, + "is_active": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "DepartmentUserAttachRequest": { + "required": [ + "user_id" + ], + "properties": { + "user_id": { + "type": "integer", + "example": 12 + }, + "is_primary": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 0, + "nullable": true + }, + "joined_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-21 10:00:00", + "nullable": true + } + }, + "type": "object" + }, + "UserBrief": { + "description": "부서원 요약", + "required": [ + "id", + "name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "example": 12 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "format": "email", + "example": "hong@example.com" + }, + "phone": { + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "is_active": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "DepartmentPermissionUpsertSingle": { + "required": [ + "permission_id" + ], + "properties": { + "permission_id": { + "type": "integer", + "example": 25 + }, + "is_allowed": { + "description": "1=ALLOW, 0=DENY(차단)", + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 1 + } + }, + "type": "object" + }, + "DepartmentPermissionUpsertMany": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DepartmentPermissionUpsertSingle" + } + } + }, + "type": "object" + }, + "DepartmentPermissionRevokeSingle": { + "required": [ + "permission_id" + ], + "properties": { + "permission_id": { + "type": "integer", + "example": 25 + } + }, + "type": "object" + }, + "DepartmentPermissionRevokeMany": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DepartmentPermissionRevokeSingle" + } + } + }, + "type": "object" + }, + "Deposit": { + "description": "입금 정보", + "properties": { + "id": { + "description": "입금 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "deposit_date": { + "description": "입금일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "description": "비회원 거래처명", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "bank_account_id": { + "description": "입금 계좌 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "payment_method": { + "description": "결제수단", + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ], + "example": "transfer" + }, + "account_code": { + "description": "계정과목", + "type": "string", + "example": "401", + "nullable": true + }, + "description": { + "description": "적요", + "type": "string", + "example": "1월 매출 입금", + "nullable": true + }, + "reference_type": { + "description": "참조 유형", + "type": "string", + "example": "sales", + "nullable": true + }, + "reference_id": { + "description": "참조 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client": { + "description": "거래처 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "(주)테스트" + } + }, + "type": "object", + "nullable": true + }, + "bank_account": { + "description": "계좌 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "bank_name": { + "type": "string", + "example": "국민은행" + }, + "account_name": { + "type": "string", + "example": "법인통장" + } + }, + "type": "object", + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "DepositCreateRequest": { + "description": "입금 등록 요청", + "required": [ + "deposit_date", + "amount", + "payment_method" + ], + "properties": { + "deposit_date": { + "description": "입금일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "description": "비회원 거래처명", + "type": "string", + "maxLength": 100, + "example": "홍길동", + "nullable": true + }, + "bank_account_id": { + "description": "입금 계좌 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "payment_method": { + "description": "결제수단", + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ], + "example": "transfer" + }, + "account_code": { + "description": "계정과목", + "type": "string", + "maxLength": 20, + "example": "401", + "nullable": true + }, + "description": { + "description": "적요", + "type": "string", + "maxLength": 1000, + "example": "1월 매출 입금", + "nullable": true + }, + "reference_type": { + "description": "참조 유형", + "type": "string", + "maxLength": 50, + "example": "sales", + "nullable": true + }, + "reference_id": { + "description": "참조 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "DepositUpdateRequest": { + "description": "입금 수정 요청", + "properties": { + "deposit_date": { + "description": "입금일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "description": "비회원 거래처명", + "type": "string", + "maxLength": 100, + "example": "홍길동", + "nullable": true + }, + "bank_account_id": { + "description": "입금 계좌 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "payment_method": { + "description": "결제수단", + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ], + "example": "transfer" + }, + "account_code": { + "description": "계정과목", + "type": "string", + "maxLength": 20, + "example": "401", + "nullable": true + }, + "description": { + "description": "적요", + "type": "string", + "maxLength": 1000, + "example": "1월 매출 입금", + "nullable": true + }, + "reference_type": { + "description": "참조 유형", + "type": "string", + "maxLength": 50, + "example": "sales", + "nullable": true + }, + "reference_id": { + "description": "참조 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "DepositSummary": { + "description": "입금 요약", + "properties": { + "total_amount": { + "description": "총 입금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "total_count": { + "description": "총 건수", + "type": "integer", + "example": 10 + }, + "by_payment_method": { + "description": "결제수단별 합계", + "properties": { + "cash": { + "properties": { + "total": { + "type": "number", + "example": 1000000 + }, + "count": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + }, + "transfer": { + "properties": { + "total": { + "type": "number", + "example": 4000000 + }, + "count": { + "type": "integer", + "example": 8 + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "DesignBomItemDiffRow": { + "properties": { + "ref_type": { + "type": "string", + "example": "MATERIAL" + }, + "ref_id": { + "type": "integer" + }, + "qty": { + "type": "number" + }, + "waste_rate": { + "type": "number" + }, + "uom_id": { + "type": "integer", + "nullable": true + }, + "notes": { + "type": "string", + "nullable": true + }, + "sort_order": { + "type": "integer" + } + }, + "type": "object" + }, + "DesignModel": { + "required": [ + "id", + "tenant_id", + "code", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 101 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "code": { + "type": "string", + "example": "KSS01" + }, + "name": { + "type": "string", + "example": "KSS 표준 모델" + }, + "category_id": { + "type": "integer", + "example": 12, + "nullable": true + }, + "lifecycle": { + "type": "string", + "example": "ACTIVE", + "nullable": true + }, + "description": { + "type": "string", + "example": "롤러 구조 표준 설계", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-09-05 10:11:12" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-09-05 10:11:12" + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "DesignModelPagination": { + "description": "라라벨 LengthAwarePaginator", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DesignModel" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/design/models?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 5 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/design/models?page=5" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/design/models?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/design/models" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 92 + } + }, + "type": "object" + }, + "ModelVersion": { + "required": [ + "id", + "tenant_id", + "model_id", + "version_no", + "status" + ], + "properties": { + "id": { + "type": "integer", + "example": 201 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "model_id": { + "type": "integer", + "example": 101 + }, + "version_no": { + "type": "integer", + "example": 1 + }, + "status": { + "type": "string", + "example": "RELEASED" + }, + "effective_from": { + "type": "string", + "format": "date-time", + "example": "2025-09-05 11:00:00", + "nullable": true + }, + "effective_to": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + }, + "notes": { + "type": "string", + "example": "초도 릴리즈", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "BomTemplate": { + "required": [ + "id", + "tenant_id", + "model_version_id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 301 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "model_version_id": { + "type": "integer", + "example": 201 + }, + "name": { + "type": "string", + "example": "Main" + }, + "is_primary": { + "type": "boolean", + "example": true + }, + "notes": { + "type": "string", + "example": "표준 템플릿", + "nullable": true + }, + "items_count": { + "description": "withCount(items) 사용 시", + "type": "integer", + "example": 3 + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "BomTemplateItem": { + "required": [ + "id", + "tenant_id", + "bom_template_id", + "ref_type", + "ref_id", + "qty" + ], + "properties": { + "id": { + "type": "integer", + "example": 401 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "bom_template_id": { + "type": "integer", + "example": 301 + }, + "ref_type": { + "type": "string", + "enum": [ + "MATERIAL", + "PRODUCT" + ], + "example": "MATERIAL" + }, + "ref_id": { + "type": "integer", + "example": 10101 + }, + "qty": { + "type": "number", + "format": "double", + "example": 2 + }, + "waste_rate": { + "type": "number", + "format": "double", + "example": 0 + }, + "uom_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "notes": { + "type": "string", + "example": "프레임용", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "BomTemplateItemReplaceRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "required": [ + "ref_type", + "ref_id", + "qty" + ], + "properties": { + "ref_type": { + "type": "string", + "enum": [ + "MATERIAL", + "PRODUCT" + ], + "example": "MATERIAL" + }, + "ref_id": { + "type": "integer", + "example": 101 + }, + "qty": { + "type": "number", + "format": "double", + "example": 2 + }, + "waste_rate": { + "type": "number", + "format": "double", + "example": 0, + "nullable": true + }, + "uom_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "notes": { + "type": "string", + "example": "프레임용", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "Document": { + "description": "문서 정보", + "properties": { + "id": { + "description": "문서 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "template_id": { + "description": "템플릿 ID", + "type": "integer", + "example": 5 + }, + "document_no": { + "description": "문서번호", + "type": "string", + "example": "DOC-20260128-0001" + }, + "title": { + "description": "문서 제목", + "type": "string", + "example": "2026년 1월 휴가 신청서" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "DRAFT", + "PENDING", + "APPROVED", + "REJECTED", + "CANCELLED" + ], + "example": "DRAFT" + }, + "linkable_type": { + "description": "연결 모델 타입", + "type": "string", + "example": "App\\\\Models\\\\Order", + "nullable": true + }, + "linkable_id": { + "description": "연결 모델 ID", + "type": "integer", + "example": 100, + "nullable": true + }, + "submitted_at": { + "description": "결재 요청일", + "type": "string", + "format": "date-time", + "example": "2026-01-28T10:00:00Z", + "nullable": true + }, + "completed_at": { + "description": "결재 완료일", + "type": "string", + "format": "date-time", + "example": "2026-01-28T15:00:00Z", + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 10 + }, + "template": { + "description": "템플릿 정보", + "properties": { + "id": { + "type": "integer", + "example": 5 + }, + "name": { + "type": "string", + "example": "휴가 신청서" + }, + "category": { + "type": "string", + "example": "HR" + } + }, + "type": "object", + "nullable": true + }, + "creator": { + "description": "생성자 정보", + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "name": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object", + "nullable": true + }, + "approvals": { + "description": "결재선", + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentApproval" + } + }, + "data": { + "description": "문서 데이터", + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentData" + } + }, + "attachments": { + "description": "첨부파일", + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentAttachment" + } + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2026-01-28T09:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2026-01-28T09:00:00Z" + } + }, + "type": "object" + }, + "DocumentApproval": { + "description": "문서 결재 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "document_id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "integer", + "example": 5 + }, + "step": { + "description": "결재 순서", + "type": "integer", + "example": 1 + }, + "role": { + "description": "역할", + "type": "string", + "example": "승인" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "PENDING", + "APPROVED", + "REJECTED" + ], + "example": "PENDING" + }, + "comment": { + "description": "결재 의견", + "type": "string", + "example": "승인합니다.", + "nullable": true + }, + "acted_at": { + "description": "결재 처리일", + "type": "string", + "format": "date-time", + "nullable": true + }, + "user": { + "description": "결재자 정보", + "properties": { + "id": { + "type": "integer", + "example": 5 + }, + "name": { + "type": "string", + "example": "김부장" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "DocumentData": { + "description": "문서 데이터 (EAV)", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "document_id": { + "type": "integer", + "example": 1 + }, + "section_id": { + "description": "섹션 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "column_id": { + "description": "컬럼 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "row_index": { + "description": "행 인덱스", + "type": "integer", + "example": 0 + }, + "field_key": { + "description": "필드 키", + "type": "string", + "example": "start_date" + }, + "field_value": { + "description": "값", + "type": "string", + "example": "2026-01-28", + "nullable": true + } + }, + "type": "object" + }, + "DocumentAttachment": { + "description": "문서 첨부파일", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "document_id": { + "type": "integer", + "example": 1 + }, + "file_id": { + "type": "integer", + "example": 100 + }, + "attachment_type": { + "description": "첨부 유형", + "type": "string", + "enum": [ + "general", + "signature", + "image", + "reference" + ], + "example": "general" + }, + "description": { + "description": "설명", + "type": "string", + "example": "증빙서류", + "nullable": true + }, + "file": { + "description": "파일 정보", + "properties": { + "id": { + "type": "integer", + "example": 100 + }, + "original_name": { + "type": "string", + "example": "document.pdf" + }, + "mime_type": { + "type": "string", + "example": "application/pdf" + }, + "size": { + "type": "integer", + "example": 1024000 + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "DocumentCreateRequest": { + "description": "문서 생성 요청", + "required": [ + "template_id", + "title" + ], + "properties": { + "template_id": { + "description": "템플릿 ID", + "type": "integer", + "example": 5 + }, + "title": { + "description": "문서 제목", + "type": "string", + "example": "2026년 1월 휴가 신청서" + }, + "linkable_type": { + "description": "연결 모델 타입", + "type": "string", + "example": "App\\\\Models\\\\Order", + "nullable": true + }, + "linkable_id": { + "description": "연결 모델 ID", + "type": "integer", + "example": 100, + "nullable": true + }, + "approvers": { + "description": "결재선", + "type": "array", + "items": { + "required": [ + "user_id" + ], + "properties": { + "user_id": { + "description": "결재자 ID", + "type": "integer", + "example": 5 + }, + "role": { + "description": "역할", + "type": "string", + "example": "승인" + } + }, + "type": "object" + } + }, + "data": { + "description": "문서 데이터", + "type": "array", + "items": { + "required": [ + "field_key" + ], + "properties": { + "section_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "column_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "row_index": { + "type": "integer", + "example": 0 + }, + "field_key": { + "type": "string", + "example": "start_date" + }, + "field_value": { + "type": "string", + "example": "2026-01-28", + "nullable": true + } + }, + "type": "object" + } + }, + "attachments": { + "description": "첨부파일", + "type": "array", + "items": { + "required": [ + "file_id" + ], + "properties": { + "file_id": { + "type": "integer", + "example": 100 + }, + "attachment_type": { + "type": "string", + "enum": [ + "general", + "signature", + "image", + "reference" + ], + "example": "general" + }, + "description": { + "type": "string", + "example": "증빙서류", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "DocumentUpdateRequest": { + "description": "문서 수정 요청", + "properties": { + "title": { + "description": "문서 제목", + "type": "string", + "example": "2026년 1월 휴가 신청서 (수정)" + }, + "linkable_type": { + "description": "연결 모델 타입", + "type": "string", + "example": "App\\\\Models\\\\Order", + "nullable": true + }, + "linkable_id": { + "description": "연결 모델 ID", + "type": "integer", + "example": 100, + "nullable": true + }, + "approvers": { + "description": "결재선 (전체 교체)", + "type": "array", + "items": { + "required": [ + "user_id" + ], + "properties": { + "user_id": { + "type": "integer", + "example": 5 + }, + "role": { + "type": "string", + "example": "승인" + } + }, + "type": "object" + } + }, + "data": { + "description": "문서 데이터 (전체 교체)", + "type": "array", + "items": { + "required": [ + "field_key" + ], + "properties": { + "section_id": { + "type": "integer", + "nullable": true + }, + "column_id": { + "type": "integer", + "nullable": true + }, + "row_index": { + "type": "integer" + }, + "field_key": { + "type": "string" + }, + "field_value": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + }, + "attachments": { + "description": "첨부파일 (전체 교체)", + "type": "array", + "items": { + "required": [ + "file_id" + ], + "properties": { + "file_id": { + "type": "integer" + }, + "attachment_type": { + "type": "string", + "enum": [ + "general", + "signature", + "image", + "reference" + ] + }, + "description": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "Employee": { + "description": "사원 정보", + "properties": { + "id": { + "description": "사원 프로필 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "user_id": { + "description": "사용자 ID", + "type": "integer", + "example": 10 + }, + "name": { + "description": "이름", + "type": "string", + "example": "홍길동" + }, + "email": { + "description": "이메일", + "type": "string", + "example": "hong@company.com" + }, + "phone": { + "description": "연락처", + "type": "string", + "example": "010-1234-5678" + }, + "department_id": { + "description": "부서 ID", + "type": "integer", + "example": 5, + "nullable": true + }, + "department_name": { + "description": "부서명", + "type": "string", + "example": "개발팀", + "nullable": true + }, + "position_key": { + "description": "직급 키", + "type": "string", + "example": "manager", + "nullable": true + }, + "job_title_key": { + "description": "직책 키", + "type": "string", + "example": "developer", + "nullable": true + }, + "work_location_key": { + "description": "근무지 키", + "type": "string", + "example": "seoul_hq", + "nullable": true + }, + "employment_type_key": { + "description": "고용형태 키", + "type": "string", + "example": "fulltime", + "nullable": true + }, + "employee_status": { + "description": "고용상태", + "type": "string", + "enum": [ + "active", + "leave", + "resigned" + ], + "example": "active" + }, + "manager_user_id": { + "description": "상급자 ID", + "type": "integer", + "example": 5, + "nullable": true + }, + "display_name": { + "description": "표시명", + "type": "string", + "example": "홍길동 매니저", + "nullable": true + }, + "profile_photo_path": { + "description": "프로필 사진 경로", + "type": "string", + "example": "/photos/hong.jpg", + "nullable": true + }, + "employee_code": { + "description": "사원번호", + "type": "string", + "example": "EMP-001", + "nullable": true + }, + "hire_date": { + "description": "입사일", + "type": "string", + "format": "date", + "example": "2020-03-15", + "nullable": true + }, + "rank": { + "description": "호봉", + "type": "string", + "example": "G3", + "nullable": true + }, + "work_type": { + "description": "근무형태", + "type": "string", + "enum": [ + "regular", + "daily", + "temporary", + "external" + ], + "example": "regular", + "nullable": true + }, + "has_account": { + "description": "시스템 계정 보유 여부", + "type": "boolean", + "example": true + }, + "is_active": { + "description": "활성 상태", + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2020-03-15T09:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-10T14:30:00Z" + } + }, + "type": "object" + }, + "EmployeeCreateRequest": { + "description": "사원 등록 요청", + "required": [ + "name", + "email" + ], + "properties": { + "user_id": { + "description": "사용자 ID (로그인 ID)", + "type": "string", + "example": "hong001" + }, + "name": { + "description": "이름", + "type": "string", + "example": "홍길동" + }, + "email": { + "description": "이메일", + "type": "string", + "format": "email", + "example": "hong@company.com" + }, + "phone": { + "description": "연락처", + "type": "string", + "example": "010-1234-5678" + }, + "password": { + "description": "초기 비밀번호 (미입력시 계정 미생성)", + "type": "string", + "example": "Password123!" + }, + "is_active": { + "description": "활성 상태", + "type": "boolean", + "example": true + }, + "department_id": { + "description": "부서 ID", + "type": "integer", + "example": 5 + }, + "position_key": { + "description": "직급 키", + "type": "string", + "example": "manager" + }, + "job_title_key": { + "description": "직책 키", + "type": "string", + "example": "developer" + }, + "work_location_key": { + "description": "근무지 키", + "type": "string", + "example": "seoul_hq" + }, + "employment_type_key": { + "description": "고용형태 키", + "type": "string", + "example": "fulltime" + }, + "employee_status": { + "description": "고용상태", + "type": "string", + "enum": [ + "active", + "leave", + "resigned" + ], + "example": "active" + }, + "manager_user_id": { + "description": "상급자 ID", + "type": "integer", + "example": 5 + }, + "display_name": { + "description": "표시명", + "type": "string", + "example": "홍길동 매니저" + }, + "employee_code": { + "description": "사원번호", + "type": "string", + "example": "EMP-001" + }, + "resident_number": { + "description": "주민번호 (암호화)", + "type": "string", + "example": "encrypted_value" + }, + "gender": { + "description": "성별", + "type": "string", + "enum": [ + "male", + "female" + ], + "example": "male" + }, + "address": { + "properties": { + "zipCode": { + "type": "string", + "example": "06234" + }, + "address1": { + "type": "string", + "example": "서울시 강남구 테헤란로 123" + }, + "address2": { + "type": "string", + "example": "10층 1001호" + } + }, + "type": "object" + }, + "salary": { + "description": "연봉", + "type": "number", + "format": "float", + "example": 50000000 + }, + "hire_date": { + "description": "입사일", + "type": "string", + "format": "date", + "example": "2020-03-15" + }, + "rank": { + "description": "호봉", + "type": "string", + "example": "G3" + }, + "bank_account": { + "properties": { + "bankName": { + "type": "string", + "example": "국민은행" + }, + "accountNumber": { + "type": "string", + "example": "123-456-789012" + }, + "accountHolder": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object" + }, + "work_type": { + "description": "근무형태", + "type": "string", + "enum": [ + "regular", + "daily", + "temporary", + "external" + ], + "example": "regular" + }, + "contract_info": { + "properties": { + "start_date": { + "type": "string", + "format": "date", + "example": "2024-01-01" + }, + "end_date": { + "type": "string", + "format": "date", + "example": "2024-12-31" + }, + "external_company": { + "type": "string", + "example": "파트너사" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "EmployeeUpdateRequest": { + "description": "사원 수정 요청", + "properties": { + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "format": "email", + "example": "hong@company.com" + }, + "phone": { + "type": "string", + "example": "010-1234-5678" + }, + "is_active": { + "type": "boolean", + "example": true + }, + "department_id": { + "type": "integer", + "example": 5 + }, + "position_key": { + "type": "string", + "example": "manager" + }, + "job_title_key": { + "type": "string", + "example": "developer" + }, + "work_location_key": { + "type": "string", + "example": "seoul_hq" + }, + "employment_type_key": { + "type": "string", + "example": "fulltime" + }, + "employee_status": { + "type": "string", + "enum": [ + "active", + "leave", + "resigned" + ], + "example": "active" + }, + "manager_user_id": { + "type": "integer", + "example": 5 + }, + "display_name": { + "type": "string", + "example": "홍길동 매니저" + }, + "employee_code": { + "type": "string", + "example": "EMP-001" + }, + "hire_date": { + "type": "string", + "format": "date", + "example": "2020-03-15" + }, + "rank": { + "type": "string", + "example": "G3" + }, + "work_type": { + "type": "string", + "enum": [ + "regular", + "daily", + "temporary", + "external" + ], + "example": "regular" + } + }, + "type": "object" + }, + "EmployeeStats": { + "description": "사원 통계", + "properties": { + "total": { + "description": "전체 사원 수", + "type": "integer", + "example": 150 + }, + "active": { + "description": "재직 중", + "type": "integer", + "example": 140 + }, + "leave": { + "description": "휴직 중", + "type": "integer", + "example": 5 + }, + "resigned": { + "description": "퇴직", + "type": "integer", + "example": 5 + }, + "has_account": { + "description": "시스템 계정 보유", + "type": "integer", + "example": 130 + }, + "no_account": { + "description": "시스템 계정 미보유", + "type": "integer", + "example": 20 + } + }, + "type": "object" + }, + "EntertainmentAmountCard": { + "description": "접대비 금액 카드", + "required": [ + "id", + "label", + "amount" + ], + "properties": { + "id": { + "description": "카드 ID", + "type": "string", + "example": "et_sales" + }, + "label": { + "description": "카드 라벨", + "type": "string", + "example": "매출" + }, + "amount": { + "description": "금액", + "type": "integer", + "example": 30530000000 + }, + "subLabel": { + "description": "부가 라벨", + "type": "string", + "example": null, + "nullable": true + }, + "unit": { + "description": "단위", + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "EntertainmentHighlightItem": { + "description": "체크포인트 하이라이트 아이템", + "required": [ + "text", + "color" + ], + "properties": { + "text": { + "description": "하이라이트 텍스트", + "type": "string", + "example": "1,000만원" + }, + "color": { + "description": "색상 (red, green, orange 등)", + "type": "string", + "example": "green" + } + }, + "type": "object" + }, + "EntertainmentCheckPoint": { + "description": "접대비 체크포인트", + "required": [ + "id", + "type", + "message" + ], + "properties": { + "id": { + "description": "체크포인트 ID", + "type": "string", + "example": "et_cp_normal" + }, + "type": { + "description": "타입 (success, warning, error)", + "type": "string", + "example": "success" + }, + "message": { + "description": "메시지", + "type": "string", + "example": "{1사분기} 접대비 사용 1,000만원 / 한도 4,012만원 (75%). 여유 있게 운영 중입니다." + }, + "highlights": { + "description": "하이라이트 아이템 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/EntertainmentHighlightItem" + } + } + }, + "type": "object" + }, + "EntertainmentSummaryResponse": { + "description": "접대비 현황 요약 응답", + "required": [ + "cards", + "check_points" + ], + "properties": { + "cards": { + "description": "금액 카드 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/EntertainmentAmountCard" + } + }, + "check_points": { + "description": "체크포인트 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/EntertainmentCheckPoint" + } + } + }, + "type": "object" + }, + "EntityRelationship": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "group_id": { + "description": "그룹 ID (1: 품목관리)", + "type": "integer", + "example": 1 + }, + "parent_type": { + "type": "string", + "enum": [ + "page", + "section" + ], + "example": "page" + }, + "parent_id": { + "type": "integer", + "example": 1 + }, + "child_type": { + "type": "string", + "enum": [ + "section", + "field", + "bom" + ], + "example": "section" + }, + "child_id": { + "type": "integer", + "example": 1 + }, + "order_no": { + "type": "integer", + "example": 0 + }, + "metadata": { + "type": "object", + "example": null, + "nullable": true + }, + "created_at": { + "type": "string", + "example": "2025-11-26 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-26 10:00:00" + } + }, + "type": "object" + }, + "LinkEntityRequest": { + "required": [ + "child_id" + ], + "properties": { + "child_id": { + "description": "연결할 엔티티 ID", + "type": "integer", + "example": 1 + }, + "order_no": { + "description": "정렬 순서", + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "ReorderRelationshipsRequest": { + "required": [ + "parent_type", + "parent_id", + "ordered_items" + ], + "properties": { + "parent_type": { + "type": "string", + "enum": [ + "page", + "section" + ], + "example": "page" + }, + "parent_id": { + "type": "integer", + "example": 1 + }, + "ordered_items": { + "type": "array", + "items": { + "properties": { + "child_type": { + "type": "string", + "example": "section" + }, + "child_id": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "PageStructure": { + "properties": { + "page": { + "$ref": "#/components/schemas/ItemPage" + }, + "sections": { + "type": "array", + "items": { + "properties": { + "section": { + "$ref": "#/components/schemas/ItemSection" + }, + "order_no": { + "type": "integer", + "example": 0 + }, + "fields": { + "type": "array", + "items": { + "type": "object" + } + }, + "bom_items": { + "type": "array", + "items": { + "type": "object" + } + } + }, + "type": "object" + } + }, + "direct_fields": { + "type": "array", + "items": { + "properties": { + "field": { + "$ref": "#/components/schemas/ItemField" + }, + "order_no": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "Estimate": { + "properties": { + "id": { + "type": "integer" + }, + "model_set_id": { + "type": "integer" + }, + "estimate_name": { + "type": "string" + }, + "customer_name": { + "type": "string", + "nullable": true + }, + "project_name": { + "type": "string", + "nullable": true + }, + "parameters": { + "type": "object" + }, + "status": { + "type": "string", + "enum": [ + "DRAFT", + "SENT", + "APPROVED", + "REJECTED", + "EXPIRED" + ] + }, + "notes": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "EstimateCreateRequest": { + "required": [ + "model_set_id", + "estimate_name", + "parameters" + ], + "properties": { + "model_set_id": { + "description": "모델셋 ID", + "type": "integer" + }, + "estimate_name": { + "description": "견적명", + "type": "string" + }, + "customer_name": { + "description": "고객명", + "type": "string" + }, + "project_name": { + "description": "프로젝트명", + "type": "string" + }, + "parameters": { + "description": "견적 파라미터", + "type": "object" + }, + "notes": { + "description": "비고", + "type": "string" + } + }, + "type": "object" + }, + "EstimateUpdateRequest": { + "properties": { + "estimate_name": { + "description": "견적명", + "type": "string" + }, + "customer_name": { + "description": "고객명", + "type": "string" + }, + "project_name": { + "description": "프로젝트명", + "type": "string" + }, + "parameters": { + "description": "견적 파라미터", + "type": "object" + }, + "status": { + "description": "견적 상태", + "type": "string" + }, + "notes": { + "description": "비고", + "type": "string" + } + }, + "type": "object" + }, + "ExpectedExpense": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "expected_payment_date": { + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "settlement_date": { + "type": "string", + "format": "date", + "example": "2025-01-10", + "nullable": true + }, + "transaction_type": { + "type": "string", + "enum": [ + "purchase", + "advance", + "suspense", + "rent", + "salary", + "insurance", + "tax", + "utilities", + "other" + ], + "example": "purchase" + }, + "amount": { + "type": "number", + "format": "float", + "example": 1500000 + }, + "client_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "type": "string", + "example": "(주)삼성전자", + "nullable": true + }, + "bank_account_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "account_code": { + "type": "string", + "example": "매입비용", + "nullable": true + }, + "payment_status": { + "type": "string", + "enum": [ + "pending", + "partial", + "paid", + "overdue" + ], + "example": "pending" + }, + "approval_status": { + "type": "string", + "enum": [ + "none", + "pending", + "approved", + "rejected" + ], + "example": "none" + }, + "description": { + "type": "string", + "example": "월정산", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "datetime" + }, + "updated_at": { + "type": "string", + "format": "datetime" + }, + "client": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + }, + "bank_account": { + "properties": { + "id": { + "type": "integer" + }, + "bank_name": { + "type": "string" + }, + "account_name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "ExpectedExpensePagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExpectedExpense" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "last_page_url": { + "type": "string" + }, + "next_page_url": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer" + }, + "prev_page_url": { + "type": "string", + "nullable": true + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + }, + "type": "object" + }, + "ExpectedExpenseCreateRequest": { + "required": [ + "expected_payment_date", + "transaction_type", + "amount" + ], + "properties": { + "expected_payment_date": { + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "settlement_date": { + "type": "string", + "format": "date", + "example": "2025-01-10", + "nullable": true + }, + "transaction_type": { + "type": "string", + "enum": [ + "purchase", + "advance", + "suspense", + "rent", + "salary", + "insurance", + "tax", + "utilities", + "other" + ], + "example": "purchase" + }, + "amount": { + "type": "number", + "format": "float", + "example": 1500000 + }, + "client_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "type": "string", + "example": "(주)삼성전자", + "nullable": true + }, + "bank_account_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "account_code": { + "type": "string", + "example": "매입비용", + "nullable": true + }, + "payment_status": { + "type": "string", + "enum": [ + "pending", + "partial", + "paid", + "overdue" + ], + "example": "pending" + }, + "approval_status": { + "type": "string", + "enum": [ + "none", + "pending", + "approved", + "rejected" + ], + "example": "none" + }, + "description": { + "type": "string", + "example": "월정산", + "nullable": true + } + }, + "type": "object" + }, + "ExpectedExpenseUpdateRequest": { + "properties": { + "expected_payment_date": { + "type": "string", + "format": "date", + "example": "2025-01-20" + }, + "settlement_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "transaction_type": { + "type": "string", + "enum": [ + "purchase", + "advance", + "suspense", + "rent", + "salary", + "insurance", + "tax", + "utilities", + "other" + ] + }, + "amount": { + "type": "number", + "format": "float" + }, + "client_id": { + "type": "integer", + "nullable": true + }, + "client_name": { + "type": "string", + "nullable": true + }, + "bank_account_id": { + "type": "integer", + "nullable": true + }, + "account_code": { + "type": "string", + "nullable": true + }, + "payment_status": { + "type": "string", + "enum": [ + "pending", + "partial", + "paid", + "overdue" + ] + }, + "approval_status": { + "type": "string", + "enum": [ + "none", + "pending", + "approved", + "rejected" + ] + }, + "description": { + "type": "string", + "nullable": true + } + }, + "type": "object" + }, + "ExpectedExpenseSummary": { + "properties": { + "total_amount": { + "type": "number", + "format": "float", + "example": 15000000 + }, + "total_count": { + "type": "integer", + "example": 12 + }, + "by_payment_status": { + "type": "object" + }, + "by_transaction_type": { + "type": "object" + }, + "by_month": { + "type": "object" + } + }, + "type": "object" + }, + "ExpectedExpenseDashboardDetail": { + "description": "CEO 대시보드 당월 예상 지출내역 me4 모달용 데이터", + "properties": { + "summary": { + "properties": { + "current_month_total": { + "description": "당월 지출예상 합계", + "type": "number", + "format": "float", + "example": 5000000 + }, + "previous_month_total": { + "description": "전월 지출예상 합계", + "type": "number", + "format": "float", + "example": 4500000 + }, + "change_rate": { + "description": "전월대비 증감률(%)", + "type": "number", + "format": "float", + "example": 11.1 + }, + "pending_balance": { + "description": "미지급 잔액", + "type": "number", + "format": "float", + "example": 3000000 + } + }, + "type": "object" + }, + "items": { + "description": "당월 지출예상 목록", + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "payment_date": { + "type": "string", + "format": "date", + "example": "2026-01-15" + }, + "item": { + "type": "string", + "example": "월 임대료" + }, + "amount": { + "type": "number", + "format": "float", + "example": 1500000 + }, + "vendor": { + "type": "string", + "example": "(주)빌딩관리" + }, + "account": { + "type": "string", + "example": "임차료" + }, + "status": { + "type": "string", + "example": "pending" + } + }, + "type": "object" + } + }, + "footer_summary": { + "properties": { + "total_amount": { + "type": "number", + "format": "float", + "example": 5000000 + }, + "total_count": { + "type": "integer", + "example": 8 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "OptionGroup": { + "required": [ + "id", + "group_key", + "name" + ], + "properties": { + "id": { + "description": "Option Group/Value 스키마", + "type": "integer", + "example": 3 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "group_key": { + "type": "string", + "example": "position" + }, + "name": { + "type": "string", + "example": "직급표(2025)" + }, + "description": { + "type": "string", + "example": "본사 기준", + "nullable": true + } + }, + "type": "object" + }, + "OptionGroupCreateRequest": { + "required": [ + "group_key", + "name" + ], + "properties": { + "group_key": { + "type": "string", + "example": "job_title" + }, + "name": { + "type": "string", + "example": "직책" + }, + "description": { + "type": "string", + "example": "영업조직용", + "nullable": true + } + }, + "type": "object" + }, + "OptionGroupUpdateRequest": { + "properties": { + "group_key": { + "type": "string", + "example": "job_title" + }, + "name": { + "type": "string", + "example": "직책(개정)" + }, + "description": { + "type": "string", + "example": "영업/CS 통합", + "nullable": true + } + }, + "type": "object" + }, + "OptionValue": { + "required": [ + "id", + "group_id", + "value_key", + "value_label" + ], + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "group_id": { + "type": "integer", + "example": 3 + }, + "value_key": { + "type": "string", + "example": "manager" + }, + "value_label": { + "type": "string", + "example": "과장" + }, + "sort_order": { + "type": "integer", + "example": 30 + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "OptionValueCreateRequest": { + "required": [ + "value_key", + "value_label" + ], + "properties": { + "value_key": { + "type": "string", + "example": "director" + }, + "value_label": { + "type": "string", + "example": "이사" + }, + "sort_order": { + "type": "integer", + "example": 40 + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "OptionValueUpdateRequest": { + "properties": { + "value_key": { + "type": "string", + "example": "director" + }, + "value_label": { + "type": "string", + "example": "이사" + }, + "sort_order": { + "type": "integer", + "example": 45 + }, + "is_active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "OptionValueReorderRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "description": "정렬 대상 목록", + "type": "array", + "items": { + "required": [ + "id", + "sort_order" + ], + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "sort_order": { + "type": "integer", + "example": 100 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "Profile": { + "description": "테넌트별 사용자 프로필", + "required": [ + "tenant_id", + "user_id" + ], + "properties": { + "id": { + "description": "Profiles 스키마", + "type": "integer", + "example": 101 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "integer", + "example": 55 + }, + "department_id": { + "type": "integer", + "example": 12, + "nullable": true + }, + "position_key": { + "type": "string", + "example": "manager", + "nullable": true + }, + "job_title_key": { + "type": "string", + "example": "lead_pm", + "nullable": true + }, + "work_location_key": { + "type": "string", + "example": "seoul_hq", + "nullable": true + }, + "employment_type_key": { + "type": "string", + "example": "regular", + "nullable": true + }, + "manager_user_id": { + "type": "integer", + "example": 77, + "nullable": true + }, + "display_name": { + "type": "string", + "example": "김철수(영업1팀)", + "nullable": true + }, + "profile_photo_path": { + "type": "string", + "example": "/uploads/tenant/1/avatar/55.png", + "nullable": true + }, + "json_extra": { + "type": "object", + "example": { + "employee_no": "A-001", + "entry_date": "2023-01-02", + "work_type": "hybrid" + }, + "nullable": true + } + }, + "type": "object" + }, + "ProfileUpdateRequest": { + "description": "프로필 수정 시, field_key: value 형태", + "type": "object", + "example": { + "position": "manager", + "employee_no": "A-001", + "entry_date": "2023-01-02", + "work_type": "hybrid" + } + }, + "ProfilePagination": { + "description": "LengthAwarePaginator 구조", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Profile" + } + }, + "total": { + "type": "integer", + "example": 3 + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "path": { + "type": "string", + "example": "/api/v1/profiles" + } + }, + "type": "object" + }, + "File": { + "description": "파일 모델", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "display_name": { + "description": "사용자에게 표시되는 파일명", + "type": "string", + "example": "계약서.pdf" + }, + "stored_name": { + "description": "실제 저장된 파일명", + "type": "string", + "example": "a1b2c3d4e5f6g7h8.pdf" + }, + "folder_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "is_temp": { + "type": "boolean", + "example": false + }, + "file_path": { + "type": "string", + "example": "1/product/2025/01/a1b2c3d4e5f6g7h8.pdf" + }, + "file_size": { + "description": "파일 크기 (bytes)", + "type": "integer", + "example": 1024000 + }, + "mime_type": { + "type": "string", + "example": "application/pdf" + }, + "file_type": { + "type": "string", + "enum": [ + "document", + "image", + "excel", + "archive" + ], + "example": "document" + }, + "document_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "document_type": { + "type": "string", + "example": null, + "nullable": true + }, + "uploaded_by": { + "type": "integer", + "example": 1 + }, + "deleted_by": { + "type": "integer", + "example": null, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-01T00:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-01T00:00:00Z" + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "FileShareLink": { + "description": "파일 공유 링크", + "properties": { + "token": { + "description": "64자 공유 토큰", + "type": "string", + "example": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" + }, + "url": { + "type": "string", + "example": "https://api.sam.kr/api/v1/files/share/a1b2c3d4" + }, + "expires_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-02T00:00:00Z" + } + }, + "type": "object" + }, + "StorageUsage": { + "description": "저장소 사용량 정보", + "properties": { + "storage_limit": { + "description": "저장소 한도 (bytes)", + "type": "integer", + "example": 10737418240 + }, + "storage_used": { + "description": "사용 중인 용량 (bytes)", + "type": "integer", + "example": 5368709120 + }, + "storage_used_formatted": { + "type": "string", + "example": "5.00 GB" + }, + "storage_limit_formatted": { + "type": "string", + "example": "10.00 GB" + }, + "usage_percentage": { + "type": "number", + "format": "float", + "example": 50 + }, + "file_count": { + "type": "integer", + "example": 150 + }, + "folder_breakdown": { + "description": "폴더별 사용량", + "type": "object", + "example": { + "product": 2147483648, + "quality": 1073741824, + "accounting": 536870912 + } + } + }, + "type": "object" + }, + "Folder": { + "description": "폴더 모델", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "folder_key": { + "description": "폴더 키 (영문 소문자, 숫자, 하이픈, 언더스코어만 허용)", + "type": "string", + "example": "product" + }, + "folder_name": { + "description": "폴더 표시명", + "type": "string", + "example": "생산관리" + }, + "description": { + "type": "string", + "maxLength": 500, + "example": "생산 관련 문서", + "nullable": true + }, + "display_order": { + "description": "정렬 순서", + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "icon": { + "type": "string", + "maxLength": 50, + "example": "icon-production", + "nullable": true + }, + "color": { + "description": "색상 코드 (#RRGGBB 형식)", + "type": "string", + "example": "#3B82F6", + "nullable": true + }, + "created_by": { + "type": "integer", + "example": 1 + }, + "updated_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-01T00:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-01T00:00:00Z" + } + }, + "type": "object" + }, + "FolderStoreRequest": { + "description": "폴더 생성 요청", + "required": [ + "folder_key", + "folder_name" + ], + "properties": { + "folder_key": { + "description": "폴더 키 (영문 소문자, 숫자, 하이픈, 언더스코어만)", + "type": "string", + "maxLength": 50, + "pattern": "^[a-z0-9_-]+$", + "example": "accounting" + }, + "folder_name": { + "description": "폴더 표시명", + "type": "string", + "maxLength": 100, + "example": "회계" + }, + "description": { + "type": "string", + "maxLength": 500, + "example": "회계 관련 문서", + "nullable": true + }, + "display_order": { + "description": "정렬 순서 (미지정 시 자동)", + "type": "integer", + "minimum": 0, + "example": 10, + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true, + "nullable": true + }, + "icon": { + "type": "string", + "maxLength": 50, + "example": "icon-accounting", + "nullable": true + }, + "color": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$", + "example": "#10B981", + "nullable": true + } + }, + "type": "object" + }, + "FolderUpdateRequest": { + "description": "폴더 수정 요청", + "properties": { + "folder_key": { + "type": "string", + "maxLength": 50, + "pattern": "^[a-z0-9_-]+$", + "example": "accounting" + }, + "folder_name": { + "type": "string", + "maxLength": 100, + "example": "회계" + }, + "description": { + "type": "string", + "maxLength": 500, + "example": "회계 관련 문서", + "nullable": true + }, + "display_order": { + "type": "integer", + "minimum": 0, + "example": 5 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "icon": { + "type": "string", + "maxLength": 50, + "example": "icon-accounting", + "nullable": true + }, + "color": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$", + "example": "#10B981", + "nullable": true + } + }, + "type": "object" + }, + "FolderReorderRequest": { + "description": "폴더 순서 변경 요청", + "required": [ + "orders" + ], + "properties": { + "orders": { + "description": "폴더 ID와 순서 배열", + "type": "array", + "items": { + "required": [ + "id", + "display_order" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "display_order": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "example": [ + { + "id": 1, + "display_order": 0 + }, + { + "id": 2, + "display_order": 1 + }, + { + "id": 3, + "display_order": 2 + } + ] + } + }, + "type": "object" + }, + "ExchangeTokenRequest": { + "required": [ + "user_id", + "tenant_id", + "exp", + "signature" + ], + "properties": { + "user_id": { + "description": "사용자 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "exp": { + "description": "만료 시간 (Unix timestamp)", + "type": "integer", + "example": 1734567890 + }, + "signature": { + "description": "HMAC 서명값", + "type": "string", + "example": "a1b2c3d4e5f6..." + } + }, + "type": "object" + }, + "ExchangeTokenResponse": { + "properties": { + "token": { + "description": "발급된 Sanctum 토큰", + "type": "string", + "example": "1|abc123def456..." + }, + "token_type": { + "description": "토큰 타입", + "type": "string", + "example": "Bearer" + }, + "expires_at": { + "description": "토큰 만료 시간", + "type": "string", + "format": "date-time", + "example": "2025-12-18 12:00:00" + } + }, + "type": "object" + }, + "ItemPage": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "page_name": { + "type": "string", + "example": "기본 정보" + }, + "item_type": { + "type": "string", + "enum": [ + "FG", + "PT", + "SM", + "RM", + "CS" + ], + "example": "FG" + }, + "absolute_path": { + "type": "string", + "example": "/items/fg/basic", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "sections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSection" + } + } + }, + "type": "object" + }, + "ItemSection": { + "description": "엔티티 - 관계는 entity_relationships로 관리", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "title": { + "type": "string", + "example": "제품 상세" + }, + "type": { + "type": "string", + "enum": [ + "fields", + "bom" + ], + "example": "fields" + }, + "order_no": { + "type": "integer", + "example": 0 + }, + "is_template": { + "description": "템플릿 여부", + "type": "boolean", + "example": false + }, + "is_default": { + "description": "기본 템플릿 여부", + "type": "boolean", + "example": false + }, + "is_locked": { + "description": "연결 잠금 여부 (init API 응답 시 포함)", + "type": "boolean", + "example": false + }, + "description": { + "type": "string", + "example": "섹션 설명", + "nullable": true + }, + "created_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemField" + } + }, + "bom_items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemBomItem" + } + } + }, + "type": "object" + }, + "ItemField": { + "description": "엔티티 - 관계는 entity_relationships로 관리", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "field_name": { + "type": "string", + "example": "제품명" + }, + "field_key": { + "description": "필드 고유 키 ({ID}_{key} 형식)", + "type": "string", + "example": "81_itemNum", + "nullable": true + }, + "field_type": { + "type": "string", + "enum": [ + "textbox", + "number", + "dropdown", + "checkbox", + "date", + "textarea" + ], + "example": "textbox" + }, + "order_no": { + "type": "integer", + "example": 0 + }, + "is_required": { + "type": "boolean", + "example": true + }, + "is_locked": { + "description": "엔티티 잠금 여부", + "type": "boolean", + "example": false + }, + "locked_by": { + "description": "잠금 설정자 ID", + "type": "integer", + "example": null, + "nullable": true + }, + "locked_at": { + "description": "잠금 설정 일시", + "type": "string", + "example": null, + "nullable": true + }, + "default_value": { + "type": "string", + "example": null, + "nullable": true + }, + "placeholder": { + "type": "string", + "example": "제품명을 입력하세요", + "nullable": true + }, + "display_condition": { + "type": "object", + "example": null, + "nullable": true + }, + "validation_rules": { + "type": "object", + "example": null, + "nullable": true + }, + "options": { + "type": "object", + "example": null, + "nullable": true + }, + "properties": { + "type": "object", + "example": null, + "nullable": true + }, + "category": { + "description": "필드 카테고리", + "type": "string", + "example": "basic", + "nullable": true + }, + "description": { + "type": "string", + "example": "필드 설명", + "nullable": true + }, + "is_common": { + "description": "공통 필드 여부", + "type": "boolean", + "example": false + }, + "created_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + } + }, + "type": "object" + }, + "ItemBomItem": { + "description": "엔티티 - 관계는 entity_relationships로 관리", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "item_code": { + "type": "string", + "example": "ITEM001", + "nullable": true + }, + "item_name": { + "type": "string", + "example": "부품 A" + }, + "quantity": { + "type": "number", + "format": "float", + "example": 1.5 + }, + "unit": { + "type": "string", + "example": "EA", + "nullable": true + }, + "unit_price": { + "type": "number", + "format": "float", + "example": 10000, + "nullable": true + }, + "total_price": { + "type": "number", + "format": "float", + "example": 15000, + "nullable": true + }, + "spec": { + "type": "string", + "example": "규격 정보", + "nullable": true + }, + "note": { + "type": "string", + "example": "비고", + "nullable": true + }, + "is_locked": { + "description": "연결 잠금 여부 (init API 응답 시 포함)", + "type": "boolean", + "example": false + }, + "created_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + } + }, + "type": "object" + }, + "SectionTemplate": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "title": { + "type": "string", + "example": "기본 템플릿" + }, + "type": { + "type": "string", + "enum": [ + "fields", + "bom" + ], + "example": "fields" + }, + "description": { + "type": "string", + "example": "설명", + "nullable": true + }, + "is_default": { + "type": "boolean", + "example": false + }, + "created_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + } + }, + "type": "object" + }, + "CustomTab": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "label": { + "type": "string", + "example": "커스텀 탭" + }, + "icon": { + "type": "string", + "example": "icon-name", + "nullable": true + }, + "is_default": { + "type": "boolean", + "example": false + }, + "order_no": { + "type": "integer", + "example": 0 + }, + "created_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "columnSetting": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "UnitOption": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "label": { + "type": "string", + "example": "개" + }, + "value": { + "type": "string", + "example": "EA" + }, + "created_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-20 10:00:00" + } + }, + "type": "object" + }, + "ItemPageStoreRequest": { + "required": [ + "page_name", + "item_type" + ], + "properties": { + "page_name": { + "type": "string", + "maxLength": 255, + "example": "기본 정보" + }, + "item_type": { + "type": "string", + "enum": [ + "FG", + "PT", + "SM", + "RM", + "CS" + ], + "example": "FG" + }, + "absolute_path": { + "type": "string", + "maxLength": 500, + "example": "/items/fg/basic", + "nullable": true + } + }, + "type": "object" + }, + "ItemPageUpdateRequest": { + "properties": { + "page_name": { + "type": "string", + "maxLength": 255, + "example": "기본 정보" + }, + "absolute_path": { + "type": "string", + "maxLength": 500, + "example": "/items/fg/basic", + "nullable": true + } + }, + "type": "object" + }, + "ItemSectionStoreRequest": { + "required": [ + "title", + "type" + ], + "properties": { + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "title": { + "type": "string", + "maxLength": 255, + "example": "제품 상세" + }, + "type": { + "type": "string", + "enum": [ + "fields", + "bom" + ], + "example": "fields" + } + }, + "type": "object" + }, + "IndependentSectionStoreRequest": { + "required": [ + "title", + "type" + ], + "properties": { + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "title": { + "type": "string", + "maxLength": 255, + "example": "섹션" + }, + "type": { + "type": "string", + "enum": [ + "fields", + "bom" + ], + "example": "fields" + }, + "is_template": { + "type": "boolean", + "example": false + }, + "is_default": { + "type": "boolean", + "example": false + }, + "description": { + "type": "string", + "example": "섹션 설명", + "nullable": true + } + }, + "type": "object" + }, + "IndependentFieldStoreRequest": { + "required": [ + "field_name", + "field_type" + ], + "properties": { + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "field_name": { + "type": "string", + "maxLength": 255, + "example": "제품명" + }, + "field_key": { + "description": "필드 고유 키 (영문+숫자+언더스코어, 저장 시 {ID}_{key} 형식으로 변환)", + "type": "string", + "maxLength": 80, + "example": "itemNum", + "nullable": true + }, + "field_type": { + "type": "string", + "enum": [ + "textbox", + "number", + "dropdown", + "checkbox", + "date", + "textarea" + ], + "example": "textbox" + }, + "is_required": { + "type": "boolean", + "example": false + }, + "default_value": { + "type": "string", + "example": null, + "nullable": true + }, + "placeholder": { + "type": "string", + "maxLength": 255, + "example": "입력하세요", + "nullable": true + }, + "display_condition": { + "type": "object", + "example": null, + "nullable": true + }, + "validation_rules": { + "type": "object", + "example": null, + "nullable": true + }, + "options": { + "type": "object", + "example": null, + "nullable": true + }, + "properties": { + "type": "object", + "example": null, + "nullable": true + }, + "is_locked": { + "description": "잠금 여부", + "type": "boolean", + "example": false, + "nullable": true + } + }, + "type": "object" + }, + "IndependentBomItemStoreRequest": { + "required": [ + "item_name" + ], + "properties": { + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "item_code": { + "type": "string", + "maxLength": 100, + "example": "ITEM001", + "nullable": true + }, + "item_name": { + "type": "string", + "maxLength": 255, + "example": "부품 A" + }, + "quantity": { + "type": "number", + "format": "float", + "example": 1 + }, + "unit": { + "type": "string", + "maxLength": 50, + "example": "EA", + "nullable": true + }, + "unit_price": { + "type": "number", + "format": "float", + "example": 10000, + "nullable": true + }, + "total_price": { + "type": "number", + "format": "float", + "example": 10000, + "nullable": true + }, + "spec": { + "type": "string", + "example": "규격", + "nullable": true + }, + "note": { + "type": "string", + "example": "비고", + "nullable": true + } + }, + "type": "object" + }, + "SectionUsageResponse": { + "description": "섹션 사용처 응답 (entity_relationships 기반)", + "properties": { + "section_id": { + "type": "integer", + "example": 1 + }, + "linked_pages": { + "type": "array", + "items": { + "type": "object" + } + }, + "total_usage_count": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + }, + "FieldUsageResponse": { + "description": "필드 사용처 응답 (entity_relationships 기반)", + "properties": { + "field_id": { + "type": "integer", + "example": 1 + }, + "linked_sections": { + "type": "array", + "items": { + "type": "object" + } + }, + "linked_pages": { + "type": "array", + "items": { + "type": "object" + } + }, + "total_usage_count": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + }, + "ItemSectionUpdateRequest": { + "properties": { + "title": { + "type": "string", + "maxLength": 255, + "example": "제품 상세" + } + }, + "type": "object" + }, + "ItemFieldStoreRequest": { + "required": [ + "field_name", + "field_type" + ], + "properties": { + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "field_name": { + "type": "string", + "maxLength": 255, + "example": "제품명" + }, + "field_key": { + "description": "필드 고유 키 (영문+숫자+언더스코어, 저장 시 {ID}_{key} 형식으로 변환)", + "type": "string", + "maxLength": 80, + "example": "itemNum", + "nullable": true + }, + "field_type": { + "type": "string", + "enum": [ + "textbox", + "number", + "dropdown", + "checkbox", + "date", + "textarea" + ], + "example": "textbox" + }, + "is_required": { + "type": "boolean", + "example": true + }, + "default_value": { + "type": "string", + "example": null, + "nullable": true + }, + "placeholder": { + "type": "string", + "maxLength": 255, + "example": "제품명을 입력하세요", + "nullable": true + }, + "display_condition": { + "type": "object", + "example": null, + "nullable": true + }, + "validation_rules": { + "type": "object", + "example": null, + "nullable": true + }, + "options": { + "type": "object", + "example": null, + "nullable": true + }, + "properties": { + "type": "object", + "example": null, + "nullable": true + }, + "is_locked": { + "description": "잠금 여부", + "type": "boolean", + "example": false, + "nullable": true + } + }, + "type": "object" + }, + "ItemFieldUpdateRequest": { + "properties": { + "field_name": { + "type": "string", + "maxLength": 255, + "example": "제품명" + }, + "field_key": { + "description": "필드 고유 키 (영문+숫자+언더스코어)", + "type": "string", + "maxLength": 80, + "example": "itemNum", + "nullable": true + }, + "field_type": { + "type": "string", + "enum": [ + "textbox", + "number", + "dropdown", + "checkbox", + "date", + "textarea" + ], + "example": "textbox" + }, + "is_required": { + "type": "boolean", + "example": true + }, + "default_value": { + "type": "string", + "example": null, + "nullable": true + }, + "placeholder": { + "type": "string", + "maxLength": 255, + "example": "제품명을 입력하세요", + "nullable": true + }, + "display_condition": { + "type": "object", + "example": null, + "nullable": true + }, + "validation_rules": { + "type": "object", + "example": null, + "nullable": true + }, + "options": { + "type": "object", + "example": null, + "nullable": true + }, + "properties": { + "type": "object", + "example": null, + "nullable": true + }, + "is_locked": { + "description": "잠금 여부", + "type": "boolean", + "example": false, + "nullable": true + } + }, + "type": "object" + }, + "ItemBomItemStoreRequest": { + "required": [ + "item_name" + ], + "properties": { + "group_id": { + "description": "계층번호", + "type": "integer", + "example": 1, + "nullable": true + }, + "item_code": { + "type": "string", + "maxLength": 100, + "example": "ITEM001", + "nullable": true + }, + "item_name": { + "type": "string", + "maxLength": 255, + "example": "부품 A" + }, + "quantity": { + "type": "number", + "format": "float", + "example": 1.5 + }, + "unit": { + "type": "string", + "maxLength": 50, + "example": "EA", + "nullable": true + }, + "unit_price": { + "type": "number", + "format": "float", + "example": 10000, + "nullable": true + }, + "total_price": { + "type": "number", + "format": "float", + "example": 15000, + "nullable": true + }, + "spec": { + "type": "string", + "example": "규격 정보", + "nullable": true + }, + "note": { + "type": "string", + "example": "비고", + "nullable": true + } + }, + "type": "object" + }, + "ItemBomItemUpdateRequest": { + "properties": { + "item_code": { + "type": "string", + "maxLength": 100, + "example": "ITEM001", + "nullable": true + }, + "item_name": { + "type": "string", + "maxLength": 255, + "example": "부품 A" + }, + "quantity": { + "type": "number", + "format": "float", + "example": 1.5 + }, + "unit": { + "type": "string", + "maxLength": 50, + "example": "EA", + "nullable": true + }, + "unit_price": { + "type": "number", + "format": "float", + "example": 10000, + "nullable": true + }, + "total_price": { + "type": "number", + "format": "float", + "example": 15000, + "nullable": true + }, + "spec": { + "type": "string", + "example": "규격 정보", + "nullable": true + }, + "note": { + "type": "string", + "example": "비고", + "nullable": true + } + }, + "type": "object" + }, + "SectionTemplateStoreRequest": { + "required": [ + "title", + "type" + ], + "properties": { + "page_id": { + "description": "연결할 페이지 ID (선택, 있으면 즉시 링크 연결)", + "type": "integer", + "example": 1, + "nullable": true + }, + "title": { + "type": "string", + "maxLength": 255, + "example": "기본 섹션" + }, + "type": { + "type": "string", + "enum": [ + "fields", + "bom" + ], + "example": "fields" + }, + "description": { + "type": "string", + "example": "설명", + "nullable": true + }, + "is_default": { + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "SectionTemplateUpdateRequest": { + "properties": { + "title": { + "type": "string", + "maxLength": 255, + "example": "기본 템플릿" + }, + "type": { + "type": "string", + "enum": [ + "fields", + "bom" + ], + "example": "fields" + }, + "description": { + "type": "string", + "example": "설명", + "nullable": true + }, + "is_default": { + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "CustomTabStoreRequest": { + "required": [ + "label" + ], + "properties": { + "label": { + "type": "string", + "maxLength": 255, + "example": "커스텀 탭" + }, + "icon": { + "type": "string", + "maxLength": 100, + "example": "icon-name", + "nullable": true + }, + "is_default": { + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "CustomTabUpdateRequest": { + "properties": { + "label": { + "type": "string", + "maxLength": 255, + "example": "커스텀 탭" + }, + "icon": { + "type": "string", + "maxLength": 100, + "example": "icon-name", + "nullable": true + }, + "is_default": { + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "UnitOptionStoreRequest": { + "required": [ + "label", + "value" + ], + "properties": { + "label": { + "type": "string", + "maxLength": 100, + "example": "개" + }, + "value": { + "type": "string", + "maxLength": 50, + "example": "EA" + } + }, + "type": "object" + }, + "ReorderRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "required": [ + "id", + "order_no" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "order_no": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "example": [ + { + "id": 1, + "order_no": 0 + }, + { + "id": 2, + "order_no": 1 + } + ] + } + }, + "type": "object" + }, + "ItemMasterInitResponse": { + "properties": { + "pages": { + "description": "페이지 목록 (linkedSections 기반)", + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemPage" + } + }, + "sections": { + "description": "모든 섹션 목록 (재사용 가능)", + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemSection" + } + }, + "fields": { + "description": "모든 필드 목록 (재사용 가능)", + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemField" + } + }, + "customTabs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomTab" + } + }, + "unitOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UnitOption" + } + } + }, + "type": "object" + }, + "Item": { + "required": [ + "id", + "code", + "name", + "item_type", + "unit" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "code": { + "type": "string", + "example": "P-001" + }, + "name": { + "type": "string", + "example": "스크린 제품 A" + }, + "item_type": { + "description": "품목 유형 (FG|PT|SM|RM|CS)", + "type": "string", + "example": "FG" + }, + "type_code": { + "description": "품목 유형 코드", + "type": "string", + "example": "FG" + }, + "unit": { + "type": "string", + "example": "EA" + }, + "category_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "specification": { + "description": "규격 (Material 전용)", + "type": "string", + "example": "1.2T x 1219 x 2438", + "nullable": true + }, + "description": { + "type": "string", + "example": "제품 설명", + "nullable": true + }, + "is_sellable": { + "type": "boolean", + "example": true + }, + "is_purchasable": { + "type": "boolean", + "example": false + }, + "is_producible": { + "type": "boolean", + "example": false + }, + "safety_stock": { + "type": "integer", + "example": 10, + "nullable": true + }, + "lead_time": { + "type": "integer", + "example": 7, + "nullable": true + }, + "is_variable_size": { + "type": "boolean", + "example": false + }, + "product_category": { + "type": "string", + "example": "SCREEN", + "nullable": true + }, + "part_type": { + "type": "string", + "example": "ASSEMBLY", + "nullable": true + }, + "item_name": { + "description": "품명 (Material 전용)", + "type": "string", + "example": "철판", + "nullable": true + }, + "is_inspection": { + "description": "검수 여부 (Material 전용)", + "type": "string", + "example": "Y", + "nullable": true + }, + "search_tag": { + "description": "검색 태그 (Material 전용)", + "type": "string", + "example": "철판,원자재,1.2T", + "nullable": true + }, + "remarks": { + "description": "비고 (Material 전용)", + "type": "string", + "example": "비고", + "nullable": true + }, + "created_at": { + "type": "string", + "example": "2025-11-14 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-14 10:10:00" + }, + "deleted_at": { + "description": "삭제일시 (soft delete)", + "type": "string", + "example": null, + "nullable": true + }, + "files": { + "description": "첨부 파일 (field_key별 그룹핑)", + "type": "object", + "example": { + "bending_diagram": [ + { + "id": 1, + "file_name": "벤딩도.pdf", + "file_path": "/uploads/items/1/bending_diagram.pdf" + } + ], + "specification": [ + { + "id": 2, + "file_name": "규격서.pdf", + "file_path": "/uploads/items/1/specification.pdf" + } + ] + }, + "nullable": true, + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemFile" + }, + "property": null + } + } + }, + "type": "object" + }, + "ItemCreateRequest": { + "required": [ + "code", + "name", + "product_type", + "unit" + ], + "properties": { + "code": { + "type": "string", + "maxLength": 50, + "example": "P-001" + }, + "name": { + "type": "string", + "maxLength": 255, + "example": "스크린 제품 A" + }, + "product_type": { + "description": "품목 유형 (FG|PT|SM|RM|CS)", + "type": "string", + "example": "FG" + }, + "unit": { + "type": "string", + "maxLength": 20, + "example": "EA" + }, + "category_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "description": { + "type": "string", + "example": "제품 설명", + "nullable": true + }, + "is_sellable": { + "type": "boolean", + "example": true, + "nullable": true + }, + "is_purchasable": { + "type": "boolean", + "example": false, + "nullable": true + }, + "is_producible": { + "type": "boolean", + "example": false, + "nullable": true + }, + "safety_stock": { + "type": "integer", + "example": 10, + "nullable": true + }, + "lead_time": { + "type": "integer", + "example": 7, + "nullable": true + }, + "is_variable_size": { + "type": "boolean", + "example": false, + "nullable": true + }, + "product_category": { + "type": "string", + "example": "SCREEN", + "nullable": true + }, + "part_type": { + "type": "string", + "example": "ASSEMBLY", + "nullable": true + }, + "attributes": { + "description": "동적 속성 (JSON)", + "type": "object", + "nullable": true + }, + "material_code": { + "description": "Material 코드 (Material 전용)", + "type": "string", + "maxLength": 50, + "example": "M-001", + "nullable": true + }, + "item_name": { + "description": "품명 (Material 전용)", + "type": "string", + "maxLength": 255, + "example": "철판", + "nullable": true + }, + "specification": { + "description": "규격 (Material 전용)", + "type": "string", + "maxLength": 255, + "example": "1.2T x 1219 x 2438", + "nullable": true + }, + "is_inspection": { + "description": "검수 여부 Y|N (Material 전용)", + "type": "string", + "example": "Y", + "nullable": true + }, + "search_tag": { + "description": "검색 태그 (Material 전용)", + "type": "string", + "maxLength": 255, + "example": "철판,원자재", + "nullable": true + }, + "remarks": { + "description": "비고 (Material 전용)", + "type": "string", + "example": "비고", + "nullable": true + }, + "options": { + "description": "옵션 (Material 전용)", + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "ItemUpdateRequest": { + "required": [ + "item_type" + ], + "properties": { + "item_type": { + "description": "품목 유형 (필수, FG|PT|SM|RM|CS)", + "type": "string", + "example": "FG" + }, + "code": { + "type": "string", + "maxLength": 50, + "example": "P-001" + }, + "name": { + "type": "string", + "maxLength": 255, + "example": "스크린 제품 A" + }, + "product_type": { + "description": "FG|PT|SM|RM|CS", + "type": "string", + "example": "FG" + }, + "unit": { + "type": "string", + "maxLength": 20, + "example": "EA" + }, + "category_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "description": { + "type": "string", + "example": "제품 설명", + "nullable": true + }, + "is_sellable": { + "type": "boolean", + "example": true, + "nullable": true + }, + "is_purchasable": { + "type": "boolean", + "example": false, + "nullable": true + }, + "is_producible": { + "type": "boolean", + "example": false, + "nullable": true + }, + "safety_stock": { + "type": "integer", + "example": 10, + "nullable": true + }, + "lead_time": { + "type": "integer", + "example": 7, + "nullable": true + }, + "is_variable_size": { + "type": "boolean", + "example": false, + "nullable": true + }, + "product_category": { + "type": "string", + "example": "SCREEN", + "nullable": true + }, + "part_type": { + "type": "string", + "example": "ASSEMBLY", + "nullable": true + }, + "attributes": { + "description": "동적 속성 (JSON)", + "type": "object", + "nullable": true + }, + "material_code": { + "description": "Material 코드 (Material 전용)", + "type": "string", + "maxLength": 50, + "example": "M-001", + "nullable": true + }, + "item_name": { + "description": "품명 (Material 전용)", + "type": "string", + "maxLength": 255, + "example": "철판", + "nullable": true + }, + "specification": { + "description": "규격 (Material 전용)", + "type": "string", + "maxLength": 255, + "example": "1.2T x 1219 x 2438", + "nullable": true + }, + "is_inspection": { + "description": "검수 여부 Y|N (Material 전용)", + "type": "string", + "example": "Y", + "nullable": true + }, + "search_tag": { + "description": "검색 태그 (Material 전용)", + "type": "string", + "maxLength": 255, + "example": "철판,원자재", + "nullable": true + }, + "remarks": { + "description": "비고 (Material 전용)", + "type": "string", + "example": "비고", + "nullable": true + }, + "options": { + "description": "옵션 (Material 전용)", + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "ItemBatchDeleteRequest": { + "required": [ + "item_type", + "ids" + ], + "properties": { + "item_type": { + "description": "품목 유형 (필수, FG|PT|SM|RM|CS)", + "type": "string", + "example": "FG" + }, + "ids": { + "description": "삭제할 품목 ID 목록", + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2, + 3 + ] + } + }, + "type": "object" + }, + "BOMLine": { + "required": [ + "id", + "ref_type", + "ref_id", + "quantity" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "ref_type": { + "description": "PRODUCT|MATERIAL", + "type": "string", + "example": "PRODUCT" + }, + "ref_id": { + "type": "integer", + "example": 10 + }, + "code": { + "type": "string", + "example": "P-001" + }, + "name": { + "type": "string", + "example": "가이드레일" + }, + "quantity": { + "type": "number", + "example": 2.5 + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "category_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "category_name": { + "type": "string", + "example": "조립품", + "nullable": true + }, + "quantity_formula": { + "description": "수량 계산 수식", + "type": "string", + "example": "W * 2", + "nullable": true + }, + "condition": { + "description": "조건부 BOM", + "type": "string", + "example": "MOTOR='Y'", + "nullable": true + } + }, + "type": "object" + }, + "BOMTree": { + "properties": { + "type": { + "type": "string", + "example": "PRODUCT" + }, + "id": { + "type": "integer", + "example": 1 + }, + "code": { + "type": "string", + "example": "P-001" + }, + "name": { + "type": "string", + "example": "스크린 세트" + }, + "quantity": { + "type": "number", + "example": 1 + }, + "depth": { + "type": "integer", + "example": 0 + }, + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BOMTree" + } + } + }, + "type": "object" + }, + "BOMCreateRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "required": [ + "ref_type", + "ref_id", + "quantity" + ], + "properties": { + "id": { + "description": "기존 라인 ID (업데이트 시)", + "type": "integer", + "example": 1, + "nullable": true + }, + "ref_type": { + "description": "PRODUCT|MATERIAL", + "type": "string", + "example": "PRODUCT" + }, + "ref_id": { + "type": "integer", + "example": 10 + }, + "quantity": { + "type": "number", + "example": 2.5 + }, + "sort_order": { + "type": "integer", + "example": 1, + "nullable": true + }, + "quantity_formula": { + "type": "string", + "example": "W * 2", + "nullable": true + }, + "condition": { + "type": "string", + "example": "MOTOR='Y'", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "BOMUpdateRequest": { + "properties": { + "ref_type": { + "description": "PRODUCT|MATERIAL", + "type": "string", + "example": "PRODUCT" + }, + "ref_id": { + "type": "integer", + "example": 10 + }, + "quantity": { + "type": "number", + "example": 2.5 + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "quantity_formula": { + "type": "string", + "example": "W * 2", + "nullable": true + }, + "condition": { + "type": "string", + "example": "MOTOR='Y'", + "nullable": true + } + }, + "type": "object" + }, + "ItemFile": { + "required": [ + "id", + "file_name", + "file_path" + ], + "properties": { + "id": { + "description": "파일 ID", + "type": "integer", + "example": 123 + }, + "file_name": { + "description": "파일명", + "type": "string", + "example": "도면_v1.pdf" + }, + "file_path": { + "description": "파일 경로", + "type": "string", + "example": "1/items/2025/12/a1b2c3d4.pdf" + }, + "file_url": { + "description": "다운로드 URL", + "type": "string", + "format": "uri", + "example": "https://api.sam.kr/api/v1/files/download/..." + }, + "file_size": { + "description": "파일 크기 (bytes)", + "type": "integer", + "example": 102400 + }, + "mime_type": { + "description": "MIME 타입", + "type": "string", + "example": "application/pdf" + }, + "field_key": { + "description": "필드 키", + "type": "string", + "example": "drawing" + }, + "created_at": { + "description": "생성일시", + "type": "string", + "format": "date-time", + "example": "2025-12-12 10:00:00" + } + }, + "type": "object" + }, + "ItemFilesGrouped": { + "description": "field_key별 그룹핑된 파일 목록", + "type": "object", + "example": { + "drawing": [ + { + "id": 10, + "file_name": "도면1.pdf", + "file_path": "..." + }, + { + "id": 11, + "file_name": "도면2.pdf", + "file_path": "..." + } + ], + "certificate": [ + { + "id": 12, + "file_name": "인증서.pdf", + "file_path": "..." + } + ] + } + }, + "ItemFileUploadRequest": { + "required": [ + "field_key", + "file" + ], + "properties": { + "field_key": { + "description": "필드 키 (자유롭게 지정)", + "type": "string", + "example": "drawing" + }, + "file": { + "description": "업로드할 파일 (최대 20MB)", + "type": "string", + "format": "binary" + }, + "file_id": { + "description": "기존 파일 ID (있으면 교체, 없으면 추가)", + "type": "integer", + "example": 123, + "nullable": true + } + }, + "type": "object" + }, + "ItemFileUploadResponse": { + "required": [ + "file_id", + "field_key", + "file_url", + "file_path", + "file_name" + ], + "properties": { + "file_id": { + "description": "파일 ID", + "type": "integer", + "example": 123 + }, + "field_key": { + "description": "필드 키", + "type": "string", + "example": "drawing" + }, + "file_url": { + "description": "다운로드 URL", + "type": "string", + "format": "uri", + "example": "https://api.sam.kr/api/v1/files/download/..." + }, + "file_path": { + "description": "파일 경로", + "type": "string", + "example": "1/items/2025/12/a1b2c3d4.pdf" + }, + "file_name": { + "description": "원본 파일명", + "type": "string", + "example": "도면_v1.pdf" + }, + "file_size": { + "description": "파일 크기 (bytes)", + "type": "integer", + "example": 102400 + }, + "mime_type": { + "description": "MIME 타입", + "type": "string", + "example": "application/pdf" + }, + "replaced": { + "description": "기존 파일 교체 여부", + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "ItemFileDeleteResponse": { + "required": [ + "file_id", + "deleted" + ], + "properties": { + "file_id": { + "description": "삭제된 파일 ID", + "type": "integer", + "example": 123 + }, + "deleted": { + "description": "삭제 성공 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "Leave": { + "description": "휴가 정보", + "properties": { + "id": { + "description": "휴가 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "user_id": { + "description": "신청자 ID", + "type": "integer", + "example": 10 + }, + "leave_type": { + "description": "휴가 유형", + "type": "string", + "enum": [ + "annual", + "half_am", + "half_pm", + "sick", + "family", + "maternity", + "parental" + ], + "example": "annual" + }, + "start_date": { + "description": "시작일", + "type": "string", + "format": "date", + "example": "2024-01-15" + }, + "end_date": { + "description": "종료일", + "type": "string", + "format": "date", + "example": "2024-01-17" + }, + "days": { + "description": "사용일수", + "type": "number", + "format": "float", + "example": 3 + }, + "reason": { + "description": "휴가 사유", + "type": "string", + "example": "개인 사유", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "pending", + "approved", + "rejected", + "cancelled" + ], + "example": "pending" + }, + "approved_by": { + "description": "승인자 ID", + "type": "integer", + "example": 5, + "nullable": true + }, + "approved_at": { + "description": "승인/반려 일시", + "type": "string", + "format": "date-time", + "example": "2024-01-14T10:00:00Z", + "nullable": true + }, + "reject_reason": { + "description": "반려 사유", + "type": "string", + "example": "인원 부족", + "nullable": true + }, + "user": { + "description": "신청자 정보", + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hong@company.com" + } + }, + "type": "object", + "nullable": true + }, + "approver": { + "description": "승인자 정보", + "properties": { + "id": { + "type": "integer", + "example": 5 + }, + "name": { + "type": "string", + "example": "김부장" + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-13T09:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-14T10:00:00Z" + } + }, + "type": "object" + }, + "LeaveCreateRequest": { + "description": "휴가 신청 요청", + "required": [ + "leave_type", + "start_date", + "end_date", + "days" + ], + "properties": { + "leave_type": { + "description": "휴가 유형", + "type": "string", + "enum": [ + "annual", + "half_am", + "half_pm", + "sick", + "family", + "maternity", + "parental" + ], + "example": "annual" + }, + "start_date": { + "description": "시작일", + "type": "string", + "format": "date", + "example": "2024-01-15" + }, + "end_date": { + "description": "종료일", + "type": "string", + "format": "date", + "example": "2024-01-17" + }, + "days": { + "description": "사용일수", + "type": "number", + "format": "float", + "maximum": 365, + "minimum": 0.5, + "example": 3 + }, + "reason": { + "description": "휴가 사유", + "type": "string", + "example": "개인 사유" + } + }, + "type": "object" + }, + "LeaveUpdateRequest": { + "description": "휴가 수정 요청", + "properties": { + "leave_type": { + "description": "휴가 유형", + "type": "string", + "enum": [ + "annual", + "half_am", + "half_pm", + "sick", + "family", + "maternity", + "parental" + ], + "example": "annual" + }, + "start_date": { + "description": "시작일", + "type": "string", + "format": "date", + "example": "2024-01-15" + }, + "end_date": { + "description": "종료일", + "type": "string", + "format": "date", + "example": "2024-01-17" + }, + "days": { + "description": "사용일수", + "type": "number", + "format": "float", + "example": 3 + }, + "reason": { + "description": "휴가 사유", + "type": "string", + "example": "개인 사유" + } + }, + "type": "object" + }, + "LeaveBalance": { + "description": "휴가 잔여일수 정보", + "properties": { + "id": { + "description": "ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "user_id": { + "description": "사용자 ID", + "type": "integer", + "example": 10 + }, + "year": { + "description": "연도", + "type": "integer", + "example": 2024 + }, + "total_days": { + "description": "연간 부여일수", + "type": "number", + "format": "float", + "example": 15 + }, + "used_days": { + "description": "사용일수", + "type": "number", + "format": "float", + "example": 5 + }, + "remaining_days": { + "description": "잔여일수", + "type": "number", + "format": "float", + "example": 10 + }, + "user": { + "description": "사용자 정보", + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "name": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "LeaveBalanceSetRequest": { + "description": "휴가 잔여일수 설정 요청", + "required": [ + "user_id", + "year", + "total_days" + ], + "properties": { + "user_id": { + "description": "사용자 ID", + "type": "integer", + "example": 10 + }, + "year": { + "description": "연도", + "type": "integer", + "maximum": 2099, + "minimum": 2020, + "example": 2024 + }, + "total_days": { + "description": "연간 부여일수", + "type": "number", + "format": "float", + "maximum": 365, + "minimum": 0, + "example": 15 + } + }, + "type": "object" + }, + "LeavePolicy": { + "description": "휴가 정책", + "properties": { + "id": { + "description": "ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "standard_type": { + "description": "기준 유형", + "type": "string", + "enum": [ + "fiscal", + "hire" + ], + "example": "fiscal" + }, + "fiscal_start_month": { + "description": "회계연도 시작 월", + "type": "integer", + "example": 1 + }, + "fiscal_start_day": { + "description": "회계연도 시작 일", + "type": "integer", + "example": 1 + }, + "default_annual_leave": { + "description": "기본 연차 일수", + "type": "integer", + "example": 15 + }, + "additional_leave_per_year": { + "description": "근속년수당 추가 연차", + "type": "integer", + "example": 1 + }, + "max_annual_leave": { + "description": "최대 연차 일수", + "type": "integer", + "example": 25 + }, + "carry_over_enabled": { + "description": "이월 허용 여부", + "type": "boolean", + "example": true + }, + "carry_over_max_days": { + "description": "최대 이월 일수", + "type": "integer", + "example": 10 + }, + "carry_over_expiry_months": { + "description": "이월 연차 소멸 기간 (개월)", + "type": "integer", + "example": 3 + }, + "created_at": { + "description": "생성일시", + "type": "string", + "format": "date-time" + }, + "updated_at": { + "description": "수정일시", + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "LeavePolicyUpdateRequest": { + "description": "휴가 정책 수정 요청", + "properties": { + "standard_type": { + "description": "기준 유형", + "type": "string", + "enum": [ + "fiscal", + "hire" + ], + "example": "fiscal" + }, + "fiscal_start_month": { + "description": "회계연도 시작 월", + "type": "integer", + "maximum": 12, + "minimum": 1, + "example": 1 + }, + "fiscal_start_day": { + "description": "회계연도 시작 일", + "type": "integer", + "maximum": 31, + "minimum": 1, + "example": 1 + }, + "default_annual_leave": { + "description": "기본 연차 일수", + "type": "integer", + "maximum": 100, + "minimum": 0, + "example": 15 + }, + "additional_leave_per_year": { + "description": "근속년수당 추가 연차", + "type": "integer", + "maximum": 10, + "minimum": 0, + "example": 1 + }, + "max_annual_leave": { + "description": "최대 연차 일수", + "type": "integer", + "maximum": 100, + "minimum": 0, + "example": 25 + }, + "carry_over_enabled": { + "description": "이월 허용 여부", + "type": "boolean", + "example": true + }, + "carry_over_max_days": { + "description": "최대 이월 일수", + "type": "integer", + "maximum": 100, + "minimum": 0, + "example": 10 + }, + "carry_over_expiry_months": { + "description": "이월 연차 소멸 기간 (개월)", + "type": "integer", + "maximum": 24, + "minimum": 0, + "example": 3 + } + }, + "type": "object" + }, + "Loan": { + "description": "가지급금 정보", + "properties": { + "id": { + "description": "가지급금 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "user_id": { + "description": "수령자 ID", + "type": "integer", + "example": 1 + }, + "loan_date": { + "description": "지급일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "amount": { + "description": "가지급금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "purpose": { + "description": "사용 목적", + "type": "string", + "example": "출장 경비", + "nullable": true + }, + "settlement_date": { + "description": "정산일", + "type": "string", + "format": "date", + "example": "2025-02-15", + "nullable": true + }, + "settlement_amount": { + "description": "정산금액", + "type": "number", + "format": "float", + "example": 5000000, + "nullable": true + }, + "status": { + "description": "상태 (미정산/정산완료/부분정산)", + "type": "string", + "enum": [ + "outstanding", + "settled", + "partial" + ], + "example": "outstanding" + }, + "status_label": { + "description": "상태 레이블", + "type": "string", + "example": "미정산" + }, + "outstanding_amount": { + "description": "미정산 잔액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "elapsed_days": { + "description": "경과일수", + "type": "integer", + "example": 30 + }, + "withdrawal_id": { + "description": "연결된 출금 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "user": { + "description": "수령자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hong@example.com" + } + }, + "type": "object", + "nullable": true + }, + "withdrawal": { + "description": "연결된 출금 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "withdrawal_date": { + "type": "string", + "format": "date" + }, + "amount": { + "type": "number", + "format": "float" + } + }, + "type": "object", + "nullable": true + }, + "creator": { + "description": "생성자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "관리자" + } + }, + "type": "object", + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "description": "수정자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "LoanCreateRequest": { + "description": "가지급금 등록 요청", + "required": [ + "user_id", + "loan_date", + "amount" + ], + "properties": { + "user_id": { + "description": "수령자 ID", + "type": "integer", + "example": 1 + }, + "loan_date": { + "description": "지급일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "amount": { + "description": "가지급금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "purpose": { + "description": "사용 목적", + "type": "string", + "maxLength": 1000, + "example": "출장 경비", + "nullable": true + }, + "withdrawal_id": { + "description": "연결할 출금 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "LoanUpdateRequest": { + "description": "가지급금 수정 요청 (미정산 상태만 수정 가능)", + "properties": { + "user_id": { + "description": "수령자 ID", + "type": "integer", + "example": 1 + }, + "loan_date": { + "description": "지급일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "amount": { + "description": "가지급금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "purpose": { + "description": "사용 목적", + "type": "string", + "maxLength": 1000, + "example": "출장 경비", + "nullable": true + }, + "withdrawal_id": { + "description": "연결할 출금 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "LoanSettleRequest": { + "description": "가지급금 정산 요청", + "required": [ + "settlement_date", + "settlement_amount" + ], + "properties": { + "settlement_date": { + "description": "정산일", + "type": "string", + "format": "date", + "example": "2025-02-15" + }, + "settlement_amount": { + "description": "정산금액", + "type": "number", + "format": "float", + "minimum": 0.01, + "example": 5000000 + } + }, + "type": "object" + }, + "LoanSummary": { + "description": "가지급금 요약", + "properties": { + "total_count": { + "description": "전체 건수", + "type": "integer", + "example": 10 + }, + "outstanding_count": { + "description": "미정산 건수", + "type": "integer", + "example": 5 + }, + "settled_count": { + "description": "정산완료 건수", + "type": "integer", + "example": 3 + }, + "partial_count": { + "description": "부분정산 건수", + "type": "integer", + "example": 2 + }, + "total_amount": { + "description": "총 가지급금액", + "type": "number", + "format": "float", + "example": 50000000 + }, + "total_settled": { + "description": "총 정산금액", + "type": "number", + "format": "float", + "example": 30000000 + }, + "total_outstanding": { + "description": "총 미정산액", + "type": "number", + "format": "float", + "example": 20000000 + } + }, + "type": "object" + }, + "LoanInterestCalculation": { + "description": "인정이자 계산 결과", + "properties": { + "year": { + "description": "계산 연도", + "type": "integer", + "example": 2025 + }, + "interest_rate": { + "description": "인정이자율 (%)", + "type": "number", + "format": "float", + "example": 4.6 + }, + "base_date": { + "description": "기준일", + "type": "string", + "format": "date", + "example": "2025-12-31" + }, + "summary": { + "description": "요약", + "properties": { + "total_balance": { + "description": "총 미정산 잔액", + "type": "number", + "format": "float", + "example": 50000000 + }, + "total_recognized_interest": { + "description": "총 인정이자", + "type": "number", + "format": "float", + "example": 2300000 + }, + "total_corporate_tax": { + "description": "법인세 추가 (19%)", + "type": "number", + "format": "float", + "example": 437000 + }, + "total_income_tax": { + "description": "소득세 추가 (35%)", + "type": "number", + "format": "float", + "example": 805000 + }, + "total_local_tax": { + "description": "지방소득세 (10%)", + "type": "number", + "format": "float", + "example": 80500 + }, + "total_tax": { + "description": "총 세금", + "type": "number", + "format": "float", + "example": 1322500 + } + }, + "type": "object" + }, + "details": { + "description": "상세 내역", + "type": "array", + "items": { + "properties": { + "loan_id": { + "type": "integer", + "example": 1 + }, + "user": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hong@example.com" + } + }, + "type": "object" + }, + "loan_date": { + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "amount": { + "type": "number", + "format": "float", + "example": 5000000 + }, + "settlement_amount": { + "type": "number", + "format": "float", + "example": 0 + }, + "outstanding_amount": { + "type": "number", + "format": "float", + "example": 5000000 + }, + "elapsed_days": { + "type": "integer", + "example": 350 + }, + "interest_rate": { + "type": "number", + "format": "float", + "example": 4.6 + }, + "recognized_interest": { + "type": "number", + "format": "float", + "example": 220548 + }, + "corporate_tax": { + "type": "number", + "format": "float", + "example": 41904 + }, + "income_tax": { + "type": "number", + "format": "float", + "example": 77192 + }, + "local_tax": { + "type": "number", + "format": "float", + "example": 7719 + }, + "total_tax": { + "type": "number", + "format": "float", + "example": 126815 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "LoanInterestReport": { + "description": "연간 인정이자 리포트", + "properties": { + "year": { + "description": "연도", + "type": "integer", + "example": 2025 + }, + "interest_rate": { + "description": "인정이자율 (%)", + "type": "number", + "format": "float", + "example": 4.6 + }, + "users": { + "description": "사용자별 내역", + "type": "array", + "items": { + "properties": { + "user": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "email": { + "type": "string", + "example": "hong@example.com" + } + }, + "type": "object" + }, + "loan_count": { + "description": "가지급금 건수", + "type": "integer", + "example": 3 + }, + "total_amount": { + "description": "총 가지급금액", + "type": "number", + "format": "float", + "example": 15000000 + }, + "total_settled": { + "description": "총 정산금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "total_outstanding": { + "description": "총 미정산액", + "type": "number", + "format": "float", + "example": 10000000 + }, + "recognized_interest": { + "description": "인정이자", + "type": "number", + "format": "float", + "example": 460000 + }, + "total_tax": { + "description": "총 세금", + "type": "number", + "format": "float", + "example": 265000 + } + }, + "type": "object" + } + }, + "grand_total": { + "description": "전체 합계", + "properties": { + "total_amount": { + "type": "number", + "format": "float", + "example": 50000000 + }, + "total_outstanding": { + "type": "number", + "format": "float", + "example": 30000000 + }, + "recognized_interest": { + "type": "number", + "format": "float", + "example": 1380000 + }, + "total_tax": { + "type": "number", + "format": "float", + "example": 795000 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "LoanDashboard": { + "description": "가지급금 대시보드 응답", + "properties": { + "summary": { + "description": "요약 정보", + "properties": { + "total_outstanding": { + "description": "미정산 가지급금 총액", + "type": "number", + "format": "float", + "example": 20000000 + }, + "recognized_interest": { + "description": "인정이자 (연 4.6%)", + "type": "number", + "format": "float", + "example": 920000 + }, + "outstanding_count": { + "description": "미정산 건수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "loans": { + "description": "최근 가지급금 목록 (미정산 우선, 최대 10건)", + "type": "array", + "items": { + "properties": { + "id": { + "description": "가지급금 ID", + "type": "integer", + "example": 1 + }, + "loan_date": { + "description": "지급일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "user_name": { + "description": "수령자명", + "type": "string", + "example": "홍길동" + }, + "category": { + "description": "구분", + "type": "string", + "enum": [ + "카드", + "계좌" + ], + "example": "카드" + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "outstanding", + "settled", + "partial" + ], + "example": "outstanding" + }, + "content": { + "description": "내용/목적", + "type": "string", + "example": "출장 경비" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "LoanTaxSimulation": { + "description": "세금 시뮬레이션 응답", + "properties": { + "year": { + "description": "시뮬레이션 연도", + "type": "integer", + "example": 2026 + }, + "loan_summary": { + "description": "가지급금 요약", + "properties": { + "total_outstanding": { + "description": "가지급금 잔액", + "type": "number", + "format": "float", + "example": 20000000 + }, + "recognized_interest": { + "description": "인정이자", + "type": "number", + "format": "float", + "example": 920000 + }, + "interest_rate": { + "description": "이자율 (%)", + "type": "number", + "format": "float", + "example": 4.6 + } + }, + "type": "object" + }, + "corporate_tax": { + "description": "법인세 비교", + "properties": { + "without_loan": { + "description": "가지급금 없을 때", + "properties": { + "taxable_income": { + "type": "number", + "format": "float", + "example": 0 + }, + "tax_amount": { + "type": "number", + "format": "float", + "example": 0 + } + }, + "type": "object" + }, + "with_loan": { + "description": "가지급금 있을 때", + "properties": { + "taxable_income": { + "type": "number", + "format": "float", + "example": 920000 + }, + "tax_amount": { + "type": "number", + "format": "float", + "example": 174800 + } + }, + "type": "object" + }, + "difference": { + "description": "차이 (가중액)", + "type": "number", + "format": "float", + "example": 174800 + }, + "rate_info": { + "description": "적용 세율 정보", + "type": "string", + "example": "법인세 19% 적용" + } + }, + "type": "object" + }, + "income_tax": { + "description": "종합소득세 비교", + "properties": { + "without_loan": { + "description": "가지급금 없을 때", + "properties": { + "taxable_income": { + "type": "number", + "format": "float", + "example": 0 + }, + "tax_rate": { + "type": "string", + "example": "0%" + }, + "tax_amount": { + "type": "number", + "format": "float", + "example": 0 + } + }, + "type": "object" + }, + "with_loan": { + "description": "가지급금 있을 때", + "properties": { + "taxable_income": { + "type": "number", + "format": "float", + "example": 920000 + }, + "tax_rate": { + "type": "string", + "example": "35%" + }, + "tax_amount": { + "type": "number", + "format": "float", + "example": 354200 + } + }, + "type": "object" + }, + "difference": { + "description": "차이", + "type": "number", + "format": "float", + "example": 354200 + }, + "breakdown": { + "description": "세부 내역", + "properties": { + "income_tax": { + "description": "소득세", + "type": "number", + "format": "float", + "example": 322000 + }, + "local_tax": { + "description": "지방소득세", + "type": "number", + "format": "float", + "example": 32200 + }, + "insurance": { + "description": "4대보험 추정", + "type": "number", + "format": "float", + "example": 82800 + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "MaterialAttribute": { + "description": "규격 정보 한 항목", + "properties": { + "label": { + "type": "string", + "example": "두께" + }, + "value": { + "type": "string", + "example": "10" + }, + "unit": { + "type": "string", + "example": "T" + } + }, + "type": "object" + }, + "Material": { + "description": "자재 상세", + "required": [ + "id", + "tenant_id", + "name", + "item_name", + "unit" + ], + "properties": { + "id": { + "type": "integer", + "example": 101 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "category_id": { + "type": "integer", + "example": 3, + "nullable": true + }, + "name": { + "type": "string", + "example": "철판" + }, + "item_name": { + "type": "string", + "example": "철판 10T 150CM" + }, + "specification": { + "type": "string", + "example": "두께 10T, 길이 150CM", + "nullable": true + }, + "material_code": { + "type": "string", + "example": null, + "nullable": true + }, + "unit": { + "type": "string", + "example": "EA" + }, + "is_inspection": { + "type": "string", + "enum": [ + "Y", + "N" + ], + "example": "N" + }, + "search_tag": { + "type": "string", + "example": "철판, 판재, 금속", + "nullable": true + }, + "remarks": { + "type": "string", + "example": "비고 메모", + "nullable": true + }, + "attributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MaterialAttribute" + }, + "nullable": true + }, + "options": { + "type": "object", + "example": { + "manufacturer": "ACME", + "color": "SILVER" + }, + "nullable": true + }, + "created_by": { + "type": "integer", + "example": 12 + }, + "updated_by": { + "type": "integer", + "example": 12, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-21 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-21 10:00:00" + } + }, + "type": "object" + }, + "MaterialBrief": { + "description": "자재 요약", + "required": [ + "id", + "name", + "item_name", + "unit" + ], + "properties": { + "id": { + "type": "integer", + "example": 101 + }, + "category_id": { + "type": "integer", + "example": 3, + "nullable": true + }, + "name": { + "type": "string", + "example": "철판" + }, + "item_name": { + "type": "string", + "example": "철판 10T 150CM" + }, + "unit": { + "type": "string", + "example": "EA" + } + }, + "type": "object" + }, + "MaterialList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MaterialBrief" + } + }, + "MaterialIndexParams": { + "properties": { + "q": { + "type": "string", + "example": "알루미늄", + "nullable": true + }, + "category": { + "type": "integer", + "example": 3, + "nullable": true + }, + "page": { + "type": "integer", + "example": 1, + "nullable": true + }, + "per_page": { + "type": "integer", + "example": 20, + "nullable": true + } + }, + "type": "object" + }, + "MaterialCreateRequest": { + "required": [ + "name", + "unit" + ], + "properties": { + "category_id": { + "type": "integer", + "example": 3, + "nullable": true + }, + "name": { + "type": "string", + "example": "철판" + }, + "unit": { + "type": "string", + "example": "EA" + }, + "is_inspection": { + "type": "string", + "enum": [ + "Y", + "N" + ], + "example": "N" + }, + "search_tag": { + "type": "string", + "example": "철판, 판재, 금속", + "nullable": true + }, + "remarks": { + "type": "string", + "example": "비고 메모", + "nullable": true + }, + "attributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MaterialAttribute" + }, + "nullable": true + }, + "options": { + "type": "object", + "example": { + "manufacturer": "ACME", + "color": "SILVER" + }, + "nullable": true + }, + "material_code": { + "type": "string", + "example": null, + "nullable": true + }, + "specification": { + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "MaterialUpdateRequest": { + "properties": { + "category_id": { + "type": "integer", + "example": 3, + "nullable": true + }, + "name": { + "type": "string", + "example": "철판(개선)", + "nullable": true + }, + "unit": { + "type": "string", + "example": "KG", + "nullable": true + }, + "is_inspection": { + "type": "string", + "enum": [ + "Y", + "N" + ], + "example": "Y", + "nullable": true + }, + "search_tag": { + "type": "string", + "example": "철판, 금속", + "nullable": true + }, + "remarks": { + "type": "string", + "example": "비고 변경", + "nullable": true + }, + "attributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MaterialAttribute" + }, + "nullable": true + }, + "options": { + "type": "object", + "example": { + "manufacturer": "ACME", + "color": "BLACK" + }, + "nullable": true + }, + "material_code": { + "type": "string", + "example": "MAT-0002", + "nullable": true + }, + "specification": { + "type": "string", + "example": "두께 12T, 길이 180CM", + "nullable": true + } + }, + "type": "object" + }, + "Menu": { + "description": "메뉴 상세", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 12 + }, + "tenant_id": { + "description": "null=공용", + "type": "integer", + "example": 1, + "nullable": true + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "type": "string", + "example": "메뉴 관리" + }, + "slug": { + "type": "string", + "example": "menu.manage", + "nullable": true + }, + "url": { + "type": "string", + "example": "/admin/menus", + "nullable": true + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "hidden": { + "type": "integer", + "example": 0 + }, + "is_external": { + "type": "integer", + "example": 0 + }, + "external_url": { + "type": "string", + "example": null, + "nullable": true + }, + "icon": { + "type": "string", + "example": "list", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-15 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-15 10:00:00" + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "MenuBrief": { + "description": "메뉴 요약", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 12 + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "type": "string", + "example": "메뉴 관리" + }, + "slug": { + "type": "string", + "example": "menu.manage", + "nullable": true + }, + "url": { + "type": "string", + "example": "/admin/menus", + "nullable": true + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "hidden": { + "type": "integer", + "example": 0 + }, + "is_external": { + "type": "integer", + "example": 0 + }, + "external_url": { + "type": "string", + "example": null, + "nullable": true + }, + "icon": { + "type": "string", + "example": "list", + "nullable": true + } + }, + "type": "object" + }, + "MenuList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MenuBrief" + } + }, + "MenuCreateRequest": { + "required": [ + "name" + ], + "properties": { + "parent_id": { + "description": "상위 메뉴 ID", + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "description": "메뉴명", + "type": "string", + "example": "새 메뉴" + }, + "slug": { + "description": "권한 키로도 활용", + "type": "string", + "example": "menu.new", + "nullable": true + }, + "url": { + "type": "string", + "example": "/admin/new", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "sort_order": { + "type": "integer", + "example": 0 + }, + "hidden": { + "type": "boolean", + "example": false + }, + "is_external": { + "type": "boolean", + "example": false + }, + "external_url": { + "type": "string", + "example": null, + "nullable": true + }, + "icon": { + "type": "string", + "example": "plus", + "nullable": true + } + }, + "type": "object" + }, + "MenuUpdateRequest": { + "properties": { + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "name": { + "type": "string", + "example": "메뉴명 변경" + }, + "slug": { + "type": "string", + "example": "menu.changed", + "nullable": true + }, + "url": { + "type": "string", + "example": "/admin/changed", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "sort_order": { + "type": "integer", + "example": 5 + }, + "hidden": { + "type": "boolean", + "example": false + }, + "is_external": { + "type": "boolean", + "example": false + }, + "external_url": { + "type": "string", + "example": null, + "nullable": true + }, + "icon": { + "type": "string", + "example": "edit", + "nullable": true + } + }, + "type": "object" + }, + "ModelSet": { + "description": "모델셋 (견적 카테고리)", + "required": [ + "id", + "code", + "name" + ], + "properties": { + "id": { + "description": "=========================\n Domain 스키마\n=========================", + "type": "integer", + "example": 1 + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "code_group": { + "type": "string", + "example": "estimate" + }, + "code": { + "type": "string", + "example": "screen_product" + }, + "name": { + "type": "string", + "example": "스크린 제품" + }, + "description": { + "type": "string", + "example": "스크린 제품군 모델셋", + "nullable": true + }, + "level": { + "type": "integer", + "example": 2 + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "profile_code": { + "type": "string", + "example": "custom_category" + }, + "is_active": { + "type": "boolean", + "example": true + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelSetField" + } + }, + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelSet" + } + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-01 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-01-01 10:00:00" + } + }, + "type": "object" + }, + "ModelSetField": { + "description": "모델셋 필드 정의", + "properties": { + "key": { + "type": "string", + "example": "open_width" + }, + "name": { + "type": "string", + "example": "열림폭" + }, + "type": { + "type": "string", + "example": "number" + }, + "required": { + "type": "boolean", + "example": true + }, + "order": { + "type": "integer", + "example": 1 + }, + "default": { + "type": "string", + "example": "1000", + "nullable": true + }, + "options": { + "type": "object", + "example": null, + "nullable": true + }, + "description": { + "type": "string", + "example": "제품 열림폭 (mm)", + "nullable": true + } + }, + "type": "object" + }, + "ModelSetDetail": { + "description": "모델셋 상세 정보", + "properties": { + "category": { + "$ref": "#/components/schemas/ModelSet" + }, + "products": { + "type": "array", + "items": { + "type": "object" + } + }, + "models": { + "type": "array", + "items": { + "type": "object" + } + }, + "field_schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelSetField" + } + } + }, + "type": "object" + }, + "ModelSetCreateRequest": { + "required": [ + "code", + "name" + ], + "properties": { + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "code": { + "type": "string", + "example": "new_product" + }, + "name": { + "type": "string", + "example": "신규 제품군" + }, + "description": { + "type": "string", + "example": "신규 제품군 설명", + "nullable": true + }, + "level": { + "type": "integer", + "example": 2 + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "profile_code": { + "type": "string", + "example": "custom_category" + }, + "is_active": { + "type": "boolean", + "example": true + }, + "fields": { + "type": "array", + "items": { + "properties": { + "key": { + "type": "string", + "example": "width" + }, + "name": { + "type": "string", + "example": "폭" + }, + "type": { + "type": "string", + "example": "number" + }, + "required": { + "type": "boolean", + "example": true + }, + "order": { + "type": "integer", + "example": 1 + }, + "default": { + "type": "string", + "nullable": true + }, + "options": { + "type": "object", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + }, + "create_model": { + "description": "기본 모델 및 BOM 템플릿 생성 여부", + "type": "boolean", + "example": false + }, + "model_data": { + "properties": { + "code": { + "type": "string", + "example": "NEW_MODEL" + }, + "name": { + "type": "string", + "example": "신규 모델" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "ModelSetUpdateRequest": { + "properties": { + "name": { + "type": "string", + "example": "수정된 제품군" + }, + "description": { + "type": "string", + "example": "수정된 설명", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 5 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "fields": { + "type": "array", + "items": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "order": { + "type": "integer" + }, + "default": { + "type": "string", + "nullable": true + }, + "options": { + "type": "object", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "ModelSetCloneRequest": { + "required": [ + "code", + "name" + ], + "properties": { + "code": { + "type": "string", + "example": "cloned_product" + }, + "name": { + "type": "string", + "example": "복제된 제품군" + }, + "description": { + "type": "string", + "example": "복제된 설명", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 999 + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "ModelSetEstimateParameters": { + "description": "견적 파라미터 정보", + "properties": { + "category": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "스크린 제품" + }, + "code": { + "type": "string", + "example": "screen_product" + } + }, + "type": "object" + }, + "input_fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelSetField" + } + }, + "calculated_fields": { + "type": "array", + "items": { + "properties": { + "key": { + "type": "string", + "example": "make_width" + }, + "name": { + "type": "string", + "example": "제작폭" + }, + "type": { + "type": "string", + "example": "number" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + }, + "calculation_schema": { + "type": "object", + "example": { + "size_calculation": "kyungdong_screen_size" + } + } + }, + "type": "object" + }, + "ModelSetBomCalculationRequest": { + "description": "BOM 계산 요청 파라미터", + "properties": { + "open_width": { + "description": "열림폭 (mm)", + "type": "number", + "example": 1500 + }, + "open_height": { + "description": "열림높이 (mm)", + "type": "number", + "example": 2000 + }, + "quantity": { + "description": "수량", + "type": "integer", + "example": 1 + }, + "model_name": { + "type": "string", + "example": "스크린A", + "nullable": true + }, + "guide_rail_type": { + "type": "string", + "example": "standard", + "nullable": true + }, + "shutter_box": { + "type": "string", + "example": "type_a", + "nullable": true + } + }, + "type": "object" + }, + "ModelSetBomCalculationResult": { + "description": "BOM 계산 결과", + "properties": { + "calculated_values": { + "properties": { + "make_width": { + "type": "number", + "example": 1530 + }, + "make_height": { + "type": "number", + "example": 2050 + }, + "calculated_area": { + "type": "number", + "example": 3.14 + }, + "calculated_weight": { + "type": "number", + "example": 45.5 + }, + "motor_capacity": { + "type": "string", + "example": "0.5HP" + }, + "motor_bracket_size": { + "type": "string", + "example": "M-100" + } + }, + "type": "object" + }, + "bom_items": { + "type": "array", + "items": { + "properties": { + "material_code": { + "type": "string", + "example": "MAT001" + }, + "material_name": { + "type": "string", + "example": "알루미늄 프레임" + }, + "quantity": { + "type": "number", + "example": 2 + }, + "unit": { + "type": "string", + "example": "EA" + }, + "unit_price": { + "type": "number", + "example": 15000 + }, + "total_price": { + "type": "number", + "example": 30000 + } + }, + "type": "object" + } + }, + "total_cost": { + "type": "number", + "example": 500000 + } + }, + "type": "object" + }, + "NotificationSettingItem": { + "properties": { + "notification_type": { + "type": "string", + "example": "approval" + }, + "label": { + "type": "string", + "example": "전자결재" + }, + "push_enabled": { + "type": "boolean", + "example": true + }, + "email_enabled": { + "type": "boolean", + "example": false + }, + "sms_enabled": { + "type": "boolean", + "example": false + }, + "in_app_enabled": { + "type": "boolean", + "example": true + }, + "kakao_enabled": { + "type": "boolean", + "example": false + }, + "settings": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "NotificationSettingResponse": { + "properties": { + "settings": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/NotificationSettingItem" + } + }, + "types": { + "description": "알림 유형 레이블", + "type": "object", + "example": { + "approval": "전자결재", + "order": "수주", + "deposit": "입금" + } + }, + "channels": { + "description": "채널 레이블", + "type": "object", + "example": { + "push": "푸시 알림", + "email": "이메일", + "sms": "SMS" + } + } + }, + "type": "object" + }, + "UpdateNotificationSettingRequest": { + "required": [ + "notification_type" + ], + "properties": { + "notification_type": { + "description": "알림 유형", + "type": "string", + "enum": [ + "approval", + "order", + "deposit", + "withdrawal", + "notice", + "system", + "marketing", + "security" + ], + "example": "approval" + }, + "push_enabled": { + "description": "푸시 알림 활성화", + "type": "boolean", + "example": true, + "nullable": true + }, + "email_enabled": { + "description": "이메일 알림 활성화", + "type": "boolean", + "example": false, + "nullable": true + }, + "sms_enabled": { + "description": "SMS 알림 활성화", + "type": "boolean", + "example": false, + "nullable": true + }, + "in_app_enabled": { + "description": "인앱 알림 활성화", + "type": "boolean", + "example": true, + "nullable": true + }, + "kakao_enabled": { + "description": "카카오 알림톡 활성화", + "type": "boolean", + "example": false, + "nullable": true + }, + "settings": { + "description": "추가 설정", + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "BulkUpdateNotificationSettingRequest": { + "required": [ + "settings" + ], + "properties": { + "settings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpdateNotificationSettingRequest" + } + } + }, + "type": "object" + }, + "NotificationSettingItemSimple": { + "description": "개별 알림 항목 설정", + "properties": { + "enabled": { + "description": "알림 활성화", + "type": "boolean", + "example": true + }, + "email": { + "description": "이메일 알림 활성화", + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "NotificationSettingGrouped": { + "description": "그룹 기반 알림 설정 (React 호환)", + "properties": { + "notice": { + "properties": { + "enabled": { + "type": "boolean", + "example": true + }, + "notice": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "event": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + } + }, + "type": "object" + }, + "schedule": { + "properties": { + "enabled": { + "type": "boolean", + "example": false + }, + "vatReport": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "incomeTaxReport": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + } + }, + "type": "object" + }, + "vendor": { + "properties": { + "enabled": { + "type": "boolean", + "example": true + }, + "newVendor": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "creditRating": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + } + }, + "type": "object" + }, + "attendance": { + "properties": { + "enabled": { + "type": "boolean", + "example": true + }, + "annualLeave": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "clockIn": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "late": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "absent": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + } + }, + "type": "object" + }, + "order": { + "properties": { + "enabled": { + "type": "boolean", + "example": true + }, + "salesOrder": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "purchaseOrder": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + } + }, + "type": "object" + }, + "approval": { + "properties": { + "enabled": { + "type": "boolean", + "example": true + }, + "approvalRequest": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "draftApproved": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "draftRejected": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "draftCompleted": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + } + }, + "type": "object" + }, + "production": { + "properties": { + "enabled": { + "type": "boolean", + "example": true + }, + "safetyStock": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + }, + "productionComplete": { + "$ref": "#/components/schemas/NotificationSettingItemSimple" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Order": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "quote_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "order_no": { + "type": "string", + "example": "ORD202501080001" + }, + "order_type_code": { + "type": "string", + "enum": [ + "ORDER", + "PURCHASE" + ], + "example": "ORDER" + }, + "status_code": { + "type": "string", + "enum": [ + "DRAFT", + "CONFIRMED", + "IN_PROGRESS", + "COMPLETED", + "CANCELLED" + ], + "example": "DRAFT" + }, + "category_code": { + "type": "string", + "example": "GENERAL", + "nullable": true + }, + "client_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "type": "string", + "example": "ABC 기업", + "nullable": true + }, + "client_contact": { + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "site_name": { + "type": "string", + "example": "강남 현장", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "float", + "example": 100 + }, + "supply_amount": { + "type": "number", + "format": "float", + "example": 1000000 + }, + "tax_amount": { + "type": "number", + "format": "float", + "example": 100000 + }, + "total_amount": { + "type": "number", + "format": "float", + "example": 1100000 + }, + "discount_rate": { + "type": "number", + "format": "float", + "example": 5, + "nullable": true + }, + "discount_amount": { + "type": "number", + "format": "float", + "example": 50000, + "nullable": true + }, + "delivery_date": { + "type": "string", + "format": "date", + "example": "2025-01-15", + "nullable": true + }, + "delivery_method_code": { + "type": "string", + "example": "DELIVERY", + "nullable": true + }, + "received_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "remarks": { + "type": "string", + "nullable": true + }, + "note": { + "type": "string", + "nullable": true + }, + "created_by": { + "type": "integer", + "nullable": true + }, + "updated_by": { + "type": "integer", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderItem" + } + }, + "client": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "OrderItem": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "order_id": { + "type": "integer", + "example": 1 + }, + "item_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "item_name": { + "type": "string", + "example": "제품A" + }, + "specification": { + "type": "string", + "example": "100x200mm", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "float", + "example": 10 + }, + "unit": { + "type": "string", + "example": "EA", + "nullable": true + }, + "unit_price": { + "type": "number", + "format": "float", + "example": 10000 + }, + "supply_amount": { + "type": "number", + "format": "float", + "example": 100000 + }, + "tax_amount": { + "type": "number", + "format": "float", + "example": 10000 + }, + "total_amount": { + "type": "number", + "format": "float", + "example": 110000 + }, + "sort_order": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "OrderPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Order" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "last_page_url": { + "type": "string" + }, + "next_page_url": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer" + }, + "prev_page_url": { + "type": "string", + "nullable": true + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + }, + "type": "object" + }, + "OrderStats": { + "properties": { + "total": { + "type": "integer", + "example": 100 + }, + "draft": { + "type": "integer", + "example": 10 + }, + "confirmed": { + "type": "integer", + "example": 30 + }, + "in_progress": { + "type": "integer", + "example": 40 + }, + "completed": { + "type": "integer", + "example": 15 + }, + "cancelled": { + "type": "integer", + "example": 5 + }, + "total_amount": { + "type": "number", + "format": "float", + "example": 50000000 + }, + "confirmed_amount": { + "type": "number", + "format": "float", + "example": 35000000 + } + }, + "type": "object" + }, + "OrderCreateRequest": { + "properties": { + "quote_id": { + "type": "integer", + "nullable": true + }, + "order_type_code": { + "type": "string", + "enum": [ + "ORDER", + "PURCHASE" + ], + "example": "ORDER" + }, + "status_code": { + "type": "string", + "enum": [ + "DRAFT", + "CONFIRMED" + ], + "example": "DRAFT" + }, + "category_code": { + "type": "string", + "nullable": true + }, + "client_id": { + "type": "integer", + "nullable": true + }, + "client_name": { + "type": "string", + "nullable": true + }, + "client_contact": { + "type": "string", + "nullable": true + }, + "site_name": { + "type": "string", + "nullable": true + }, + "delivery_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "delivery_method_code": { + "type": "string", + "nullable": true + }, + "received_at": { + "type": "string", + "format": "date", + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "remarks": { + "type": "string", + "nullable": true + }, + "note": { + "type": "string", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderItemRequest" + } + } + }, + "type": "object" + }, + "OrderUpdateRequest": { + "properties": { + "order_type_code": { + "type": "string", + "enum": [ + "ORDER", + "PURCHASE" + ] + }, + "category_code": { + "type": "string", + "nullable": true + }, + "client_id": { + "type": "integer", + "nullable": true + }, + "client_name": { + "type": "string", + "nullable": true + }, + "client_contact": { + "type": "string", + "nullable": true + }, + "site_name": { + "type": "string", + "nullable": true + }, + "delivery_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "delivery_method_code": { + "type": "string", + "nullable": true + }, + "received_at": { + "type": "string", + "format": "date", + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "remarks": { + "type": "string", + "nullable": true + }, + "note": { + "type": "string", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderItemRequest" + }, + "nullable": true + } + }, + "type": "object" + }, + "OrderItemRequest": { + "required": [ + "item_name", + "quantity", + "unit_price" + ], + "properties": { + "item_id": { + "type": "integer", + "nullable": true + }, + "item_name": { + "type": "string", + "example": "제품A" + }, + "specification": { + "type": "string", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "float", + "example": 10 + }, + "unit": { + "type": "string", + "example": "EA", + "nullable": true + }, + "unit_price": { + "type": "number", + "format": "float", + "example": 10000 + } + }, + "type": "object" + }, + "OrderStatusRequest": { + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "DRAFT", + "CONFIRMED", + "IN_PROGRESS", + "COMPLETED", + "CANCELLED" + ], + "example": "CONFIRMED" + } + }, + "type": "object" + }, + "Payment": { + "description": "결제 정보", + "properties": { + "id": { + "description": "결제 ID", + "type": "integer", + "example": 1 + }, + "subscription_id": { + "description": "구독 ID", + "type": "integer", + "example": 1 + }, + "amount": { + "description": "결제 금액", + "type": "number", + "format": "float", + "example": 29000 + }, + "payment_method": { + "description": "결제 수단", + "type": "string", + "enum": [ + "card", + "bank", + "virtual", + "cash", + "free" + ], + "example": "card" + }, + "payment_method_label": { + "description": "결제 수단 라벨", + "type": "string", + "example": "카드" + }, + "transaction_id": { + "description": "PG 거래 ID", + "type": "string", + "example": "TXN123456789", + "nullable": true + }, + "paid_at": { + "description": "결제일시", + "type": "string", + "format": "date-time", + "example": "2025-01-15T10:30:00", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "pending", + "completed", + "failed", + "cancelled", + "refunded" + ], + "example": "completed" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "완료" + }, + "memo": { + "description": "메모", + "type": "string", + "example": "정기 결제", + "nullable": true + }, + "formatted_amount": { + "description": "포맷된 금액", + "type": "string", + "example": "29,000원" + }, + "is_completed": { + "description": "완료 여부", + "type": "boolean", + "example": true + }, + "is_refundable": { + "description": "환불 가능 여부", + "type": "boolean", + "example": true + }, + "subscription": { + "description": "구독 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "plan": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "스타터" + }, + "code": { + "type": "string", + "example": "starter" + } + }, + "type": "object" + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "PaymentCreateRequest": { + "description": "결제 등록 요청 (수동)", + "required": [ + "subscription_id", + "amount", + "payment_method" + ], + "properties": { + "subscription_id": { + "description": "구독 ID", + "type": "integer", + "example": 1 + }, + "amount": { + "description": "결제 금액", + "type": "number", + "format": "float", + "minimum": 0, + "example": 29000 + }, + "payment_method": { + "description": "결제 수단", + "type": "string", + "enum": [ + "card", + "bank", + "virtual", + "cash", + "free" + ], + "example": "card" + }, + "transaction_id": { + "description": "PG 거래 ID", + "type": "string", + "maxLength": 100, + "example": "TXN123456789", + "nullable": true + }, + "memo": { + "description": "메모", + "type": "string", + "maxLength": 500, + "example": "정기 결제", + "nullable": true + }, + "auto_complete": { + "description": "자동 완료 처리", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "PaymentActionRequest": { + "description": "결제 액션 요청", + "properties": { + "reason": { + "description": "사유", + "type": "string", + "maxLength": 500, + "example": "고객 요청", + "nullable": true + }, + "transaction_id": { + "description": "PG 거래 ID", + "type": "string", + "maxLength": 100, + "example": "TXN123456789", + "nullable": true + } + }, + "type": "object" + }, + "PaymentSummary": { + "description": "결제 요약 통계", + "properties": { + "total_count": { + "description": "전체 건수", + "type": "integer", + "example": 50 + }, + "completed_count": { + "description": "완료 건수", + "type": "integer", + "example": 45 + }, + "pending_count": { + "description": "대기 건수", + "type": "integer", + "example": 2 + }, + "failed_count": { + "description": "실패 건수", + "type": "integer", + "example": 1 + }, + "cancelled_count": { + "description": "취소 건수", + "type": "integer", + "example": 1 + }, + "refunded_count": { + "description": "환불 건수", + "type": "integer", + "example": 1 + }, + "total_completed_amount": { + "description": "완료 총액", + "type": "number", + "format": "float", + "example": 1305000 + }, + "total_refunded_amount": { + "description": "환불 총액", + "type": "number", + "format": "float", + "example": 29000 + }, + "net_amount": { + "description": "순 금액", + "type": "number", + "format": "float", + "example": 1276000 + }, + "by_method": { + "description": "결제 수단별 집계", + "properties": { + "card": { + "properties": { + "count": { + "type": "integer", + "example": 40 + }, + "total_amount": { + "type": "number", + "format": "float", + "example": 1160000 + } + }, + "type": "object" + }, + "bank": { + "properties": { + "count": { + "type": "integer", + "example": 5 + }, + "total_amount": { + "type": "number", + "format": "float", + "example": 145000 + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "PaymentStatement": { + "description": "결제 명세서", + "properties": { + "statement_no": { + "description": "명세서 번호", + "type": "string", + "example": "INV-20250115-000001" + }, + "issued_at": { + "description": "발행일시", + "type": "string", + "format": "date-time" + }, + "payment": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "amount": { + "type": "number", + "format": "float", + "example": 29000 + }, + "formatted_amount": { + "type": "string", + "example": "29,000원" + }, + "payment_method": { + "type": "string", + "example": "card" + }, + "payment_method_label": { + "type": "string", + "example": "카드" + }, + "transaction_id": { + "type": "string", + "example": "TXN123456789", + "nullable": true + }, + "status": { + "type": "string", + "example": "completed" + }, + "status_label": { + "type": "string", + "example": "완료" + }, + "paid_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + } + }, + "type": "object" + }, + "subscription": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "started_at": { + "type": "string", + "format": "date", + "example": "2025-01-01" + }, + "ended_at": { + "type": "string", + "format": "date", + "example": "2025-02-01", + "nullable": true + }, + "status": { + "type": "string", + "example": "active" + }, + "status_label": { + "type": "string", + "example": "활성" + } + }, + "type": "object" + }, + "plan": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "스타터" + }, + "code": { + "type": "string", + "example": "starter" + }, + "price": { + "type": "number", + "format": "float", + "example": 29000 + }, + "billing_cycle": { + "type": "string", + "example": "monthly" + }, + "billing_cycle_label": { + "type": "string", + "example": "월간" + } + }, + "type": "object", + "nullable": true + }, + "customer": { + "properties": { + "tenant_id": { + "type": "integer", + "example": 1 + }, + "company_name": { + "type": "string", + "example": "테스트 회사" + }, + "business_number": { + "type": "string", + "example": "123-45-67890", + "nullable": true + }, + "representative": { + "type": "string", + "example": "홍길동", + "nullable": true + }, + "address": { + "type": "string", + "example": "서울시 강남구", + "nullable": true + }, + "email": { + "type": "string", + "example": "contact@test.com", + "nullable": true + }, + "phone": { + "type": "string", + "example": "02-1234-5678", + "nullable": true + } + }, + "type": "object" + }, + "items": { + "type": "array", + "items": { + "properties": { + "description": { + "type": "string", + "example": "스타터 구독 (2025.01.01)" + }, + "quantity": { + "type": "integer", + "example": 1 + }, + "unit_price": { + "type": "number", + "format": "float", + "example": 29000 + }, + "amount": { + "type": "number", + "format": "float", + "example": 29000 + } + }, + "type": "object" + } + }, + "subtotal": { + "description": "소계", + "type": "number", + "format": "float", + "example": 29000 + }, + "tax": { + "description": "세금", + "type": "number", + "format": "float", + "example": 0 + }, + "total": { + "description": "총액", + "type": "number", + "format": "float", + "example": 29000 + } + }, + "type": "object" + }, + "Payroll": { + "description": "급여 정보", + "properties": { + "id": { + "description": "급여 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "user_id": { + "description": "직원 ID", + "type": "integer", + "example": 10 + }, + "pay_year": { + "description": "지급 연도", + "type": "integer", + "example": 2024 + }, + "pay_month": { + "description": "지급 월", + "type": "integer", + "example": 12 + }, + "base_salary": { + "description": "기본급", + "type": "number", + "format": "float", + "example": 3000000 + }, + "overtime_pay": { + "description": "연장근무수당", + "type": "number", + "format": "float", + "example": 200000, + "nullable": true + }, + "bonus": { + "description": "상여금", + "type": "number", + "format": "float", + "example": 500000, + "nullable": true + }, + "allowances": { + "description": "수당 목록", + "type": "array", + "items": { + "properties": { + "name": { + "type": "string", + "example": "식대" + }, + "amount": { + "type": "number", + "example": 100000 + } + }, + "type": "object" + }, + "nullable": true + }, + "gross_salary": { + "description": "총 지급액", + "type": "number", + "format": "float", + "example": 3800000 + }, + "income_tax": { + "description": "소득세", + "type": "number", + "format": "float", + "example": 80000 + }, + "resident_tax": { + "description": "주민세", + "type": "number", + "format": "float", + "example": 8000 + }, + "health_insurance": { + "description": "건강보험료", + "type": "number", + "format": "float", + "example": 120000 + }, + "pension": { + "description": "국민연금", + "type": "number", + "format": "float", + "example": 135000 + }, + "employment_insurance": { + "description": "고용보험료", + "type": "number", + "format": "float", + "example": 30400 + }, + "deductions": { + "description": "기타 공제 목록", + "type": "array", + "items": { + "properties": { + "name": { + "type": "string", + "example": "조합비" + }, + "amount": { + "type": "number", + "example": 10000 + } + }, + "type": "object" + }, + "nullable": true + }, + "total_deductions": { + "description": "총 공제액", + "type": "number", + "format": "float", + "example": 383400 + }, + "net_salary": { + "description": "실수령액", + "type": "number", + "format": "float", + "example": 3416600 + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "draft", + "confirmed", + "paid" + ], + "example": "draft" + }, + "confirmed_at": { + "description": "확정일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "confirmed_by": { + "description": "확정자 ID", + "type": "integer", + "nullable": true + }, + "paid_at": { + "description": "지급일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "withdrawal_id": { + "description": "출금 내역 ID", + "type": "integer", + "nullable": true + }, + "note": { + "description": "비고", + "type": "string", + "nullable": true + }, + "user": { + "description": "직원 정보", + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "name": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T09:00:00Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T09:00:00Z" + } + }, + "type": "object" + }, + "PayrollStoreRequest": { + "description": "급여 생성 요청", + "required": [ + "user_id", + "pay_year", + "pay_month", + "base_salary" + ], + "properties": { + "user_id": { + "description": "직원 ID", + "type": "integer", + "example": 10 + }, + "pay_year": { + "description": "지급 연도 (2000-2100)", + "type": "integer", + "example": 2024 + }, + "pay_month": { + "description": "지급 월 (1-12)", + "type": "integer", + "example": 12 + }, + "base_salary": { + "description": "기본급", + "type": "number", + "example": 3000000 + }, + "overtime_pay": { + "description": "연장근무수당", + "type": "number", + "example": 200000 + }, + "bonus": { + "description": "상여금", + "type": "number", + "example": 500000 + }, + "allowances": { + "description": "수당 목록", + "type": "array", + "items": { + "properties": { + "name": { + "type": "string", + "example": "식대" + }, + "amount": { + "type": "number", + "example": 100000 + } + }, + "type": "object" + } + }, + "income_tax": { + "description": "소득세", + "type": "number", + "example": 80000 + }, + "resident_tax": { + "description": "주민세", + "type": "number", + "example": 8000 + }, + "health_insurance": { + "description": "건강보험료", + "type": "number", + "example": 120000 + }, + "pension": { + "description": "국민연금", + "type": "number", + "example": 135000 + }, + "employment_insurance": { + "description": "고용보험료", + "type": "number", + "example": 30400 + }, + "deductions": { + "description": "기타 공제 목록", + "type": "array", + "items": { + "properties": { + "name": { + "type": "string", + "example": "조합비" + }, + "amount": { + "type": "number", + "example": 10000 + } + }, + "type": "object" + } + }, + "note": { + "description": "비고", + "type": "string", + "example": "비고" + } + }, + "type": "object" + }, + "PayrollUpdateRequest": { + "description": "급여 수정 요청 (작성중 상태만 가능)", + "properties": { + "user_id": { + "description": "직원 ID", + "type": "integer", + "example": 10 + }, + "pay_year": { + "description": "지급 연도", + "type": "integer", + "example": 2024 + }, + "pay_month": { + "description": "지급 월", + "type": "integer", + "example": 12 + }, + "base_salary": { + "description": "기본급", + "type": "number", + "example": 3000000 + }, + "overtime_pay": { + "description": "연장근무수당", + "type": "number", + "example": 200000 + }, + "bonus": { + "description": "상여금", + "type": "number", + "example": 500000 + }, + "allowances": { + "description": "수당 목록", + "type": "array", + "items": { + "type": "object" + } + }, + "income_tax": { + "description": "소득세", + "type": "number", + "example": 80000 + }, + "resident_tax": { + "description": "주민세", + "type": "number", + "example": 8000 + }, + "health_insurance": { + "description": "건강보험료", + "type": "number", + "example": 120000 + }, + "pension": { + "description": "국민연금", + "type": "number", + "example": 135000 + }, + "employment_insurance": { + "description": "고용보험료", + "type": "number", + "example": 30400 + }, + "deductions": { + "description": "기타 공제 목록", + "type": "array", + "items": { + "type": "object" + } + }, + "note": { + "description": "비고", + "type": "string", + "example": "비고" + } + }, + "type": "object" + }, + "PayrollCalculateRequest": { + "description": "급여 일괄 계산 요청", + "required": [ + "year", + "month" + ], + "properties": { + "year": { + "description": "지급 연도", + "type": "integer", + "example": 2024 + }, + "month": { + "description": "지급 월", + "type": "integer", + "example": 12 + }, + "user_ids": { + "description": "직원 ID 목록 (미지정시 전체)", + "type": "array", + "items": { + "type": "integer" + } + } + }, + "type": "object" + }, + "PayrollSummary": { + "description": "급여 현황 요약", + "properties": { + "draft": { + "description": "작성중", + "type": "integer", + "example": 10 + }, + "confirmed": { + "description": "확정", + "type": "integer", + "example": 45 + }, + "paid": { + "description": "지급완료", + "type": "integer", + "example": 40 + }, + "total_gross": { + "description": "총 지급액 합계", + "type": "number", + "example": 150000000 + }, + "total_net": { + "description": "총 실수령액 합계", + "type": "number", + "example": 130000000 + } + }, + "type": "object" + }, + "PayrollSetting": { + "description": "급여 설정", + "properties": { + "id": { + "description": "설정 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "income_tax_rate": { + "description": "소득세율 (%)", + "type": "number", + "example": 3.3 + }, + "resident_tax_rate": { + "description": "주민세율 (소득세 대비 %)", + "type": "number", + "example": 10 + }, + "health_insurance_rate": { + "description": "건강보험요율 (%)", + "type": "number", + "example": 3.545 + }, + "long_term_care_rate": { + "description": "장기요양보험요율 (건강보험 대비 %)", + "type": "number", + "example": 12.95 + }, + "pension_rate": { + "description": "국민연금요율 (%)", + "type": "number", + "example": 4.5 + }, + "employment_insurance_rate": { + "description": "고용보험요율 (%)", + "type": "number", + "example": 0.9 + }, + "pension_max_salary": { + "description": "국민연금 상한기준", + "type": "number", + "example": 5900000 + }, + "pension_min_salary": { + "description": "국민연금 하한기준", + "type": "number", + "example": 370000 + }, + "pay_day": { + "description": "급여 지급일", + "type": "integer", + "example": 25 + }, + "auto_calculate": { + "description": "자동계산 여부", + "type": "boolean", + "example": true + }, + "allowance_types": { + "description": "수당 유형 목록", + "type": "array", + "items": { + "properties": { + "code": { + "type": "string", + "example": "MEAL" + }, + "name": { + "type": "string", + "example": "식대" + }, + "is_taxable": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "deduction_types": { + "description": "공제 유형 목록", + "type": "array", + "items": { + "properties": { + "code": { + "type": "string", + "example": "UNION" + }, + "name": { + "type": "string", + "example": "조합비" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "PayrollSettingUpdateRequest": { + "description": "급여 설정 수정 요청", + "properties": { + "income_tax_rate": { + "description": "소득세율", + "type": "number", + "example": 3.3 + }, + "resident_tax_rate": { + "description": "주민세율", + "type": "number", + "example": 10 + }, + "health_insurance_rate": { + "description": "건강보험요율", + "type": "number", + "example": 3.545 + }, + "long_term_care_rate": { + "description": "장기요양보험요율", + "type": "number", + "example": 12.95 + }, + "pension_rate": { + "description": "국민연금요율", + "type": "number", + "example": 4.5 + }, + "employment_insurance_rate": { + "description": "고용보험요율", + "type": "number", + "example": 0.9 + }, + "pension_max_salary": { + "description": "국민연금 상한기준", + "type": "number", + "example": 5900000 + }, + "pension_min_salary": { + "description": "국민연금 하한기준", + "type": "number", + "example": 370000 + }, + "pay_day": { + "description": "급여 지급일 (1-31)", + "type": "integer", + "example": 25 + }, + "auto_calculate": { + "description": "자동계산 여부", + "type": "boolean", + "example": true + }, + "allowance_types": { + "description": "수당 유형 목록", + "type": "array", + "items": { + "type": "object" + } + }, + "deduction_types": { + "description": "공제 유형 목록", + "type": "array", + "items": { + "type": "object" + } + } + }, + "type": "object" + }, + "Payslip": { + "description": "급여명세서", + "properties": { + "employee": { + "description": "직원 정보", + "properties": { + "id": { + "type": "integer", + "example": 10 + }, + "name": { + "type": "string", + "example": "홍길동" + }, + "employee_number": { + "type": "string", + "example": "EMP001" + }, + "department": { + "type": "string", + "example": "개발팀" + }, + "position": { + "type": "string", + "example": "과장" + } + }, + "type": "object" + }, + "period": { + "description": "급여 기간", + "type": "string", + "example": "2024년 12월" + }, + "pay_date": { + "description": "지급일", + "type": "string", + "format": "date", + "example": "2024-12-25" + }, + "earnings": { + "description": "지급 내역", + "properties": { + "base_salary": { + "type": "number", + "example": 3000000 + }, + "overtime_pay": { + "type": "number", + "example": 200000 + }, + "bonus": { + "type": "number", + "example": 500000 + }, + "allowances": { + "type": "array", + "items": { + "type": "object" + } + }, + "total": { + "type": "number", + "example": 3800000 + } + }, + "type": "object" + }, + "deductions": { + "description": "공제 내역", + "properties": { + "income_tax": { + "type": "number", + "example": 80000 + }, + "resident_tax": { + "type": "number", + "example": 8000 + }, + "health_insurance": { + "type": "number", + "example": 120000 + }, + "pension": { + "type": "number", + "example": 135000 + }, + "employment_insurance": { + "type": "number", + "example": 30400 + }, + "others": { + "type": "array", + "items": { + "type": "object" + } + }, + "total": { + "type": "number", + "example": 383400 + } + }, + "type": "object" + }, + "net_salary": { + "description": "실수령액", + "type": "number", + "example": 3416600 + } + }, + "type": "object" + }, + "MenuMatrixAction": { + "properties": { + "permission_id": { + "type": "integer", + "example": 1 + }, + "permission_code": { + "type": "string", + "example": "menu:16.view" + }, + "guard_name": { + "type": "string", + "example": "api" + }, + "state": { + "type": "string", + "enum": [ + "allow", + "deny", + "none" + ], + "example": "allow" + }, + "is_allowed": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "example": 1 + } + }, + "type": "object" + }, + "MenuMatrixNode": { + "properties": { + "menu_id": { + "type": "integer", + "example": 16 + }, + "parent_id": { + "type": "integer", + "example": 10, + "nullable": true + }, + "name": { + "type": "string", + "example": "스크린 작업" + }, + "path": { + "type": "string", + "example": "/tenant/production/screen_work.php" + }, + "type": { + "type": "string", + "example": "workflow" + }, + "actions": { + "properties": { + "view": { + "$ref": "#/components/schemas/MenuMatrixAction" + }, + "create": { + "$ref": "#/components/schemas/MenuMatrixAction" + }, + "update": { + "$ref": "#/components/schemas/MenuMatrixAction" + }, + "delete": { + "$ref": "#/components/schemas/MenuMatrixAction" + }, + "approve": { + "$ref": "#/components/schemas/MenuMatrixAction" + } + }, + "type": "object" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MenuMatrixNode" + } + } + }, + "type": "object" + }, + "MenuMatrixPayload": { + "properties": { + "actions": { + "type": "array", + "items": { + "type": "string", + "example": "view" + } + }, + "tree": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MenuMatrixNode" + } + } + }, + "type": "object" + }, + "Plan": { + "description": "요금제 정보", + "properties": { + "id": { + "description": "요금제 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "요금제명", + "type": "string", + "example": "스타터" + }, + "code": { + "description": "요금제 코드", + "type": "string", + "example": "starter" + }, + "description": { + "description": "설명", + "type": "string", + "example": "기본 기능을 제공하는 요금제입니다.", + "nullable": true + }, + "price": { + "description": "가격", + "type": "number", + "format": "float", + "example": 29000 + }, + "billing_cycle": { + "description": "결제 주기", + "type": "string", + "enum": [ + "monthly", + "yearly", + "lifetime" + ], + "example": "monthly" + }, + "billing_cycle_label": { + "description": "결제 주기 라벨", + "type": "string", + "example": "월간" + }, + "features": { + "description": "기능 목록", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "사용자 5명", + "저장공간 10GB" + ], + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + }, + "formatted_price": { + "description": "포맷된 가격", + "type": "string", + "example": "29,000원" + }, + "active_subscriptions_count": { + "description": "활성 구독 수", + "type": "integer", + "example": 15 + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "PlanCreateRequest": { + "description": "요금제 등록 요청", + "required": [ + "name", + "code", + "price", + "billing_cycle" + ], + "properties": { + "name": { + "description": "요금제명", + "type": "string", + "maxLength": 100, + "example": "스타터" + }, + "code": { + "description": "요금제 코드 (unique)", + "type": "string", + "maxLength": 50, + "example": "starter" + }, + "description": { + "description": "설명", + "type": "string", + "maxLength": 500, + "example": "기본 기능을 제공하는 요금제입니다.", + "nullable": true + }, + "price": { + "description": "가격", + "type": "number", + "format": "float", + "minimum": 0, + "example": 29000 + }, + "billing_cycle": { + "description": "결제 주기", + "type": "string", + "enum": [ + "monthly", + "yearly", + "lifetime" + ], + "example": "monthly" + }, + "features": { + "description": "기능 목록", + "type": "array", + "items": { + "type": "string", + "maxLength": 200 + }, + "example": [ + "사용자 5명", + "저장공간 10GB" + ], + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "PlanUpdateRequest": { + "description": "요금제 수정 요청", + "properties": { + "name": { + "description": "요금제명", + "type": "string", + "maxLength": 100, + "example": "스타터" + }, + "code": { + "description": "요금제 코드", + "type": "string", + "maxLength": 50, + "example": "starter" + }, + "description": { + "description": "설명", + "type": "string", + "maxLength": 500, + "example": "기본 기능을 제공하는 요금제입니다.", + "nullable": true + }, + "price": { + "description": "가격", + "type": "number", + "format": "float", + "minimum": 0, + "example": 29000 + }, + "billing_cycle": { + "description": "결제 주기", + "type": "string", + "enum": [ + "monthly", + "yearly", + "lifetime" + ], + "example": "monthly" + }, + "features": { + "description": "기능 목록", + "type": "array", + "items": { + "type": "string", + "maxLength": 200 + }, + "nullable": true + }, + "is_active": { + "description": "활성 여부", + "type": "boolean" + } + }, + "type": "object" + }, + "Popup": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "target_type": { + "description": "대상 유형", + "type": "string", + "enum": [ + "all", + "department" + ], + "example": "all" + }, + "target_id": { + "description": "대상 ID (부서 ID)", + "type": "integer", + "example": null, + "nullable": true + }, + "title": { + "description": "제목", + "type": "string", + "example": "공지사항 팝업" + }, + "content": { + "description": "내용 (HTML)", + "type": "string", + "example": "

팝업 내용입니다.

" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "active" + }, + "started_at": { + "description": "노출 시작일", + "type": "string", + "format": "date-time", + "example": "2025-01-01T00:00:00", + "nullable": true + }, + "ended_at": { + "description": "노출 종료일", + "type": "string", + "format": "date-time", + "example": "2025-12-31T23:59:59", + "nullable": true + }, + "options": { + "description": "확장 옵션", + "type": "object", + "nullable": true + }, + "created_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "type": "integer", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "creator": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + }, + "department": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "PopupPagination": { + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + }, + { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Popup" + } + } + }, + "type": "object" + } + ] + }, + "PopupCreateRequest": { + "required": [ + "title", + "content" + ], + "properties": { + "target_type": { + "description": "대상 유형 (기본: all)", + "type": "string", + "enum": [ + "all", + "department" + ], + "example": "all" + }, + "target_id": { + "description": "대상 부서 ID (target_type=department 시 필수)", + "type": "integer", + "example": null, + "nullable": true + }, + "title": { + "description": "제목", + "type": "string", + "maxLength": 200, + "example": "새 공지사항" + }, + "content": { + "description": "내용 (HTML)", + "type": "string", + "example": "

팝업 내용

" + }, + "status": { + "description": "상태 (기본: inactive)", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "inactive" + }, + "started_at": { + "description": "노출 시작일", + "type": "string", + "format": "date", + "example": "2025-01-01", + "nullable": true + }, + "ended_at": { + "description": "노출 종료일", + "type": "string", + "format": "date", + "example": "2025-12-31", + "nullable": true + }, + "options": { + "description": "확장 옵션", + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "PopupUpdateRequest": { + "properties": { + "target_type": { + "description": "대상 유형", + "type": "string", + "enum": [ + "all", + "department" + ], + "example": "department" + }, + "target_id": { + "description": "대상 부서 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "title": { + "description": "제목", + "type": "string", + "maxLength": 200, + "example": "수정된 공지사항" + }, + "content": { + "description": "내용 (HTML)", + "type": "string", + "example": "

수정된 내용

" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "active", + "inactive" + ], + "example": "active" + }, + "started_at": { + "description": "노출 시작일", + "type": "string", + "format": "date", + "example": "2025-01-01", + "nullable": true + }, + "ended_at": { + "description": "노출 종료일", + "type": "string", + "format": "date", + "example": "2025-12-31", + "nullable": true + }, + "options": { + "description": "확장 옵션", + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "Position": { + "required": [ + "id", + "tenant_id", + "type", + "name", + "sort_order", + "is_active" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 287 + }, + "type": { + "description": "유형: rank(직급), title(직책)", + "type": "string", + "enum": [ + "rank", + "title" + ], + "example": "rank" + }, + "name": { + "description": "명칭", + "type": "string", + "example": "대리" + }, + "sort_order": { + "description": "정렬 순서", + "type": "integer", + "example": 2 + }, + "is_active": { + "description": "활성화 여부", + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "PositionCreateRequest": { + "required": [ + "type", + "name" + ], + "properties": { + "type": { + "description": "유형: rank(직급), title(직책)", + "type": "string", + "enum": [ + "rank", + "title" + ], + "example": "rank" + }, + "name": { + "description": "명칭", + "type": "string", + "example": "과장" + }, + "sort_order": { + "description": "정렬 순서 (생략시 자동)", + "type": "integer", + "example": 3 + }, + "is_active": { + "description": "활성화 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "PositionUpdateRequest": { + "properties": { + "name": { + "description": "명칭", + "type": "string", + "example": "과장" + }, + "sort_order": { + "description": "정렬 순서", + "type": "integer", + "example": 3 + }, + "is_active": { + "description": "활성화 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "PositionReorderRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "required": [ + "id", + "sort_order" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "Post": { + "required": [ + "id", + "board_id", + "title" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "board_id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "description": "작성자 ID", + "type": "integer", + "example": 1 + }, + "title": { + "description": "제목", + "type": "string", + "example": "공지사항 제목" + }, + "content": { + "description": "내용", + "type": "string", + "example": "공지사항 내용입니다." + }, + "editor_type": { + "type": "string", + "enum": [ + "wysiwyg", + "markdown", + "text" + ], + "example": "wysiwyg" + }, + "ip_address": { + "type": "string", + "example": "127.0.0.1", + "nullable": true + }, + "is_notice": { + "description": "공지 여부", + "type": "boolean", + "example": false + }, + "is_secret": { + "description": "비밀글 여부", + "type": "boolean", + "example": false + }, + "views": { + "description": "조회수", + "type": "integer", + "example": 0 + }, + "status": { + "type": "string", + "enum": [ + "draft", + "published", + "hidden" + ], + "example": "published" + }, + "created_at": { + "type": "string", + "example": "2025-01-01 12:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-01-01 12:00:00" + }, + "board": { + "$ref": "#/components/schemas/Board" + }, + "files": { + "type": "array", + "items": { + "type": "object" + } + } + }, + "type": "object" + }, + "PostPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Post" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string" + }, + "next_page_url": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer", + "example": 15 + }, + "prev_page_url": { + "type": "string", + "nullable": true + }, + "to": { + "type": "integer", + "example": 15 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + }, + "PostCreateRequest": { + "required": [ + "title", + "content" + ], + "properties": { + "title": { + "type": "string", + "maxLength": 200, + "example": "게시글 제목" + }, + "content": { + "type": "string", + "example": "게시글 내용입니다." + }, + "editor_type": { + "type": "string", + "enum": [ + "wysiwyg", + "markdown", + "text" + ], + "example": "wysiwyg" + }, + "is_notice": { + "type": "boolean", + "example": false + }, + "is_secret": { + "type": "boolean", + "example": false + }, + "status": { + "type": "string", + "enum": [ + "draft", + "published", + "hidden" + ], + "example": "published" + }, + "custom_fields": { + "description": "커스텀 필드 값 (field_id: value)", + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "PostUpdateRequest": { + "properties": { + "title": { + "type": "string", + "maxLength": 200 + }, + "content": { + "type": "string" + }, + "editor_type": { + "type": "string", + "enum": [ + "wysiwyg", + "markdown", + "text" + ] + }, + "is_notice": { + "type": "boolean" + }, + "is_secret": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "draft", + "published", + "hidden" + ] + }, + "custom_fields": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "Comment": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "post_id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "integer", + "example": 1 + }, + "parent_id": { + "description": "부모 댓글 ID (대댓글인 경우)", + "type": "integer", + "nullable": true + }, + "content": { + "type": "string", + "example": "댓글 내용" + }, + "status": { + "type": "string", + "enum": [ + "active", + "deleted" + ], + "example": "active" + }, + "created_at": { + "type": "string", + "example": "2025-01-01 12:00:00" + }, + "replies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Comment" + } + } + }, + "type": "object" + }, + "CommentCreateRequest": { + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string", + "maxLength": 2000, + "example": "댓글 내용" + }, + "parent_id": { + "description": "대댓글인 경우 부모 댓글 ID", + "type": "integer", + "nullable": true + } + }, + "type": "object" + }, + "Price": { + "description": "단가 마스터", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "item_type_code": { + "description": "품목 유형", + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ], + "example": "PRODUCT" + }, + "item_id": { + "description": "품목 ID", + "type": "integer", + "example": 10 + }, + "client_group_id": { + "description": "고객그룹 ID (NULL=기본가)", + "type": "integer", + "example": 1, + "nullable": true + }, + "purchase_price": { + "description": "매입단가 (표준원가)", + "type": "number", + "format": "decimal", + "example": 10000, + "nullable": true + }, + "processing_cost": { + "description": "가공비", + "type": "number", + "format": "decimal", + "example": 2000, + "nullable": true + }, + "loss_rate": { + "description": "LOSS율 (%)", + "type": "number", + "format": "decimal", + "example": 5, + "nullable": true + }, + "margin_rate": { + "description": "마진율 (%)", + "type": "number", + "format": "decimal", + "example": 25, + "nullable": true + }, + "sales_price": { + "description": "판매단가", + "type": "number", + "format": "decimal", + "example": 15800, + "nullable": true + }, + "rounding_rule": { + "description": "반올림 규칙", + "type": "string", + "enum": [ + "round", + "ceil", + "floor" + ], + "example": "round" + }, + "rounding_unit": { + "description": "반올림 단위 (1,10,100,1000)", + "type": "integer", + "example": 100 + }, + "supplier": { + "description": "공급업체", + "type": "string", + "example": "ABC공급", + "nullable": true + }, + "effective_from": { + "description": "적용 시작일", + "type": "string", + "format": "date", + "example": "2025-01-01" + }, + "effective_to": { + "description": "적용 종료일", + "type": "string", + "format": "date", + "example": "2025-12-31", + "nullable": true + }, + "note": { + "description": "비고", + "type": "string", + "example": "2025년 상반기 가격", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "draft", + "active", + "inactive", + "finalized" + ], + "example": "active" + }, + "is_final": { + "description": "최종 확정 여부", + "type": "boolean", + "example": false + }, + "finalized_at": { + "description": "확정 일시", + "type": "string", + "format": "datetime", + "example": "2025-01-15 10:30:00", + "nullable": true + }, + "finalized_by": { + "description": "확정자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "example": "2025-01-01 12:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-01-01 12:00:00" + }, + "client_group": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "VIP 고객" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "PricePagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Price" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/pricing?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/pricing?page=3" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "nullable": true + }, + "label": { + "type": "string" + }, + "active": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/pricing" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + }, + "PriceRevision": { + "description": "단가 변경 이력", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "price_id": { + "type": "integer", + "example": 1 + }, + "revision_number": { + "description": "리비전 번호", + "type": "integer", + "example": 1 + }, + "changed_at": { + "description": "변경 일시", + "type": "string", + "format": "datetime", + "example": "2025-01-01 12:00:00" + }, + "changed_by": { + "description": "변경자 ID", + "type": "integer", + "example": 1 + }, + "change_reason": { + "description": "변경 사유", + "type": "string", + "example": "2025년 단가 인상", + "nullable": true + }, + "before_snapshot": { + "description": "변경 전 데이터", + "type": "object", + "nullable": true + }, + "after_snapshot": { + "description": "변경 후 데이터", + "type": "object" + }, + "changed_by_user": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "홍길동" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "PriceStoreRequest": { + "required": [ + "item_type_code", + "item_id", + "effective_from" + ], + "properties": { + "item_type_code": { + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ], + "example": "PRODUCT" + }, + "item_id": { + "type": "integer", + "example": 10 + }, + "client_group_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "purchase_price": { + "type": "number", + "example": 10000, + "nullable": true + }, + "processing_cost": { + "type": "number", + "example": 2000, + "nullable": true + }, + "loss_rate": { + "type": "number", + "example": 5, + "nullable": true + }, + "margin_rate": { + "type": "number", + "example": 25, + "nullable": true + }, + "sales_price": { + "type": "number", + "example": 15800, + "nullable": true + }, + "rounding_rule": { + "type": "string", + "enum": [ + "round", + "ceil", + "floor" + ], + "example": "round" + }, + "rounding_unit": { + "type": "integer", + "enum": [ + 1, + 10, + 100, + 1000 + ], + "example": 100 + }, + "supplier": { + "type": "string", + "example": "ABC공급", + "nullable": true + }, + "effective_from": { + "type": "string", + "format": "date", + "example": "2025-01-01" + }, + "effective_to": { + "type": "string", + "format": "date", + "example": "2025-12-31", + "nullable": true + }, + "note": { + "type": "string", + "example": "2025년 상반기 가격", + "nullable": true + }, + "status": { + "type": "string", + "enum": [ + "draft", + "active", + "inactive" + ], + "example": "draft" + } + }, + "type": "object" + }, + "PriceUpdateRequest": { + "properties": { + "item_type_code": { + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ], + "example": "PRODUCT" + }, + "item_id": { + "type": "integer", + "example": 10 + }, + "client_group_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "purchase_price": { + "type": "number", + "example": 10000, + "nullable": true + }, + "processing_cost": { + "type": "number", + "example": 2000, + "nullable": true + }, + "loss_rate": { + "type": "number", + "example": 5, + "nullable": true + }, + "margin_rate": { + "type": "number", + "example": 25, + "nullable": true + }, + "sales_price": { + "type": "number", + "example": 15800, + "nullable": true + }, + "rounding_rule": { + "type": "string", + "enum": [ + "round", + "ceil", + "floor" + ], + "example": "round" + }, + "rounding_unit": { + "type": "integer", + "enum": [ + 1, + 10, + 100, + 1000 + ], + "example": 100 + }, + "supplier": { + "type": "string", + "example": "ABC공급", + "nullable": true + }, + "effective_from": { + "type": "string", + "format": "date", + "example": "2025-01-01" + }, + "effective_to": { + "type": "string", + "format": "date", + "example": "2025-12-31", + "nullable": true + }, + "note": { + "type": "string", + "example": "2025년 상반기 가격", + "nullable": true + }, + "status": { + "type": "string", + "enum": [ + "draft", + "active", + "inactive" + ], + "example": "active" + }, + "change_reason": { + "description": "변경 사유 (리비전 기록용)", + "type": "string", + "example": "단가 인상", + "nullable": true + } + }, + "type": "object" + }, + "PriceByItemsRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "properties": { + "item_type_code": { + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ], + "example": "PRODUCT" + }, + "item_id": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "client_group_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "date": { + "type": "string", + "format": "date", + "example": "2025-01-15", + "nullable": true + } + }, + "type": "object" + }, + "PriceByItemsResult": { + "type": "array", + "items": { + "properties": { + "item_type_code": { + "type": "string", + "example": "PRODUCT" + }, + "item_id": { + "type": "integer", + "example": 10 + }, + "price": { + "oneOf": [ + { + "$ref": "#/components/schemas/Price" + } + ], + "nullable": true + }, + "has_price": { + "type": "boolean", + "example": true + } + }, + "type": "object" + } + }, + "PriceCostResult": { + "properties": { + "item_type_code": { + "type": "string", + "example": "MATERIAL" + }, + "item_id": { + "type": "integer", + "example": 123 + }, + "date": { + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "cost_source": { + "description": "원가 출처", + "type": "string", + "enum": [ + "receipt", + "standard", + "not_found" + ], + "example": "receipt" + }, + "purchase_price": { + "type": "number", + "example": 10500, + "nullable": true + }, + "receipt_id": { + "description": "수입검사 ID (cost_source=receipt일 때)", + "type": "integer", + "example": 456, + "nullable": true + }, + "receipt_date": { + "type": "string", + "format": "date", + "example": "2025-01-10", + "nullable": true + }, + "price_id": { + "description": "단가 ID (cost_source=standard일 때)", + "type": "integer", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "ProcessItem": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "process_id": { + "type": "integer", + "example": 1 + }, + "item_id": { + "type": "integer", + "example": 123 + }, + "priority": { + "type": "integer", + "example": 0 + }, + "is_active": { + "type": "boolean", + "example": true + }, + "item": { + "properties": { + "id": { + "type": "integer", + "example": 123 + }, + "code": { + "type": "string", + "example": "ITEM-001" + }, + "name": { + "type": "string", + "example": "품목명" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ProcessClassificationRule": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "process_id": { + "type": "integer", + "example": 1 + }, + "registration_type": { + "type": "string", + "example": "pattern" + }, + "rule_type": { + "type": "string", + "enum": [ + "품목코드", + "품목명", + "품목구분" + ] + }, + "matching_type": { + "type": "string", + "enum": [ + "startsWith", + "endsWith", + "contains", + "equals" + ] + }, + "condition_value": { + "type": "string", + "example": "SCR-" + }, + "priority": { + "type": "integer", + "example": 0 + }, + "description": { + "type": "string", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "Process": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "process_code": { + "type": "string", + "example": "P-001" + }, + "process_name": { + "type": "string", + "example": "스크린 생산" + }, + "description": { + "type": "string", + "nullable": true + }, + "process_type": { + "type": "string", + "enum": [ + "생산", + "검사", + "포장", + "조립" + ] + }, + "department": { + "type": "string", + "nullable": true + }, + "work_log_template": { + "type": "string", + "nullable": true + }, + "required_workers": { + "type": "integer", + "example": 1 + }, + "equipment_info": { + "type": "string", + "nullable": true + }, + "work_steps": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "note": { + "type": "string", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "classification_rules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProcessClassificationRule" + } + }, + "process_items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProcessItem" + } + } + }, + "type": "object" + }, + "ProcessCreateRequest": { + "required": [ + "process_name", + "process_type" + ], + "properties": { + "process_name": { + "type": "string", + "maxLength": 100, + "example": "스크린 생산" + }, + "description": { + "type": "string", + "nullable": true + }, + "process_type": { + "type": "string", + "enum": [ + "생산", + "검사", + "포장", + "조립" + ] + }, + "department": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "work_log_template": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "required_workers": { + "type": "integer", + "minimum": 1, + "nullable": true + }, + "equipment_info": { + "type": "string", + "maxLength": 255, + "nullable": true + }, + "work_steps": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "note": { + "type": "string", + "nullable": true + }, + "is_active": { + "type": "boolean", + "nullable": true + }, + "classification_rules": { + "description": "패턴 기반 분류 규칙", + "type": "array", + "items": { + "required": [ + "rule_type", + "matching_type", + "condition_value" + ], + "properties": { + "rule_type": { + "type": "string", + "enum": [ + "품목코드", + "품목명", + "품목구분" + ] + }, + "matching_type": { + "type": "string", + "enum": [ + "startsWith", + "endsWith", + "contains", + "equals" + ] + }, + "condition_value": { + "type": "string", + "maxLength": 255 + }, + "priority": { + "type": "integer", + "minimum": 0 + }, + "description": { + "type": "string", + "maxLength": 255, + "nullable": true + }, + "is_active": { + "type": "boolean" + } + }, + "type": "object" + }, + "nullable": true + }, + "item_ids": { + "description": "개별 품목 ID 배열", + "type": "array", + "items": { + "type": "integer", + "example": 123 + }, + "nullable": true + } + }, + "type": "object" + }, + "BomTreeNode": { + "description": "BOM 트리 한 노드(제품/자재 공통)", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "type": { + "description": "PRODUCT / MATERIAL 등", + "type": "string", + "example": "PRODUCT" + }, + "code": { + "type": "string", + "example": "PRD-001" + }, + "name": { + "type": "string", + "example": "스크린 모듈 KS001" + }, + "unit": { + "type": "string", + "example": "SET", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "float", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 0 + }, + "category": { + "properties": { + "id": { + "type": "integer", + "example": 2, + "nullable": true + }, + "name": { + "type": "string", + "example": "본체", + "nullable": true + } + }, + "type": "object", + "nullable": true + }, + "children": { + "description": "자식 노드 목록(없으면 빈 배열)", + "type": "array", + "items": { + "$ref": "#/components/schemas/BomTreeNode" + } + } + }, + "type": "object" + }, + "BomCategoryStat": { + "properties": { + "category_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "category_name": { + "type": "string", + "example": "기본" + }, + "count": { + "description": "해당 카테고리를 사용하는 BOM 항목 수(빈도)", + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "BomReplaceItem": { + "required": [ + "ref_type", + "ref_id", + "quantity" + ], + "properties": { + "ref_type": { + "description": "참조 타입", + "type": "string", + "enum": [ + "MATERIAL", + "PRODUCT" + ], + "example": "MATERIAL" + }, + "ref_id": { + "description": "참조 ID (materials.id 또는 products.id)", + "type": "integer", + "example": 201 + }, + "quantity": { + "description": "수량(0 이상, 소수 허용)", + "type": "number", + "format": "float", + "example": 2 + }, + "sort_order": { + "description": "정렬 순서(선택)", + "type": "integer", + "example": 0, + "nullable": true + } + }, + "type": "object" + }, + "BomReplaceCategory": { + "required": [ + "items" + ], + "properties": { + "id": { + "description": "프론트 임시 카테고리 ID(선택)", + "type": "integer", + "example": 1, + "nullable": true + }, + "name": { + "description": "프론트 카테고리명(선택)", + "type": "string", + "example": "기본", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BomReplaceItem" + } + } + }, + "type": "object" + }, + "BomReplaceRequest": { + "required": [ + "categories" + ], + "properties": { + "categories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BomReplaceCategory" + } + } + }, + "type": "object", + "example": { + "categories": [ + { + "id": 1, + "name": "기본", + "items": [ + { + "ref_type": "MATERIAL", + "ref_id": 201, + "quantity": 2, + "sort_order": 0 + }, + { + "ref_type": "PRODUCT", + "ref_id": 301, + "quantity": 1 + } + ] + }, + { + "id": 2, + "name": "옵션", + "items": [ + { + "ref_type": "MATERIAL", + "ref_id": 202, + "quantity": 5 + } + ] + } + ] + } + }, + "BomReplaceResult": { + "properties": { + "deleted_count": { + "description": "삭제된 기존 항목 수", + "type": "integer", + "example": 5 + }, + "inserted_count": { + "description": "신규로 삽입된 항목 수", + "type": "integer", + "example": 7 + } + }, + "type": "object" + }, + "ProductCategory": { + "required": [ + "id", + "code_group", + "code", + "name", + "is_active", + "sort_order" + ], + "properties": { + "id": { + "description": "제품 카테고리 스키마", + "type": "integer", + "example": 4 + }, + "code_group": { + "type": "string", + "example": "category" + }, + "code": { + "type": "string", + "example": "BP" + }, + "name": { + "type": "string", + "example": "절곡판" + }, + "parent_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "attributes": { + "type": "object", + "example": { + "color": "blue", + "flags": { + "screen": true + } + }, + "nullable": true + }, + "description": { + "type": "string", + "example": "절곡판", + "nullable": true + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "sort_order": { + "type": "integer", + "example": 10 + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-07-23T09:00:00+09:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-07-23T09:00:00+09:00" + } + }, + "type": "object" + }, + "Product": { + "required": [ + "id", + "tenant_id", + "code", + "name", + "category_id", + "product_type", + "is_active" + ], + "properties": { + "id": { + "description": "제품 관련 스키마들", + "type": "integer", + "example": 101 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "code": { + "type": "string", + "example": "PRD-001" + }, + "name": { + "type": "string", + "example": "스크린 모듈 KS001" + }, + "category_id": { + "type": "integer", + "example": 7 + }, + "product_type": { + "type": "string", + "example": "PRODUCT" + }, + "attributes": { + "type": "object", + "example": { + "color": "black", + "size": "L" + }, + "nullable": true + }, + "description": { + "type": "string", + "example": "고객사 스펙", + "nullable": true + }, + "is_sellable": { + "type": "integer", + "example": 1 + }, + "is_purchasable": { + "type": "integer", + "example": 0 + }, + "is_producible": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "integer", + "example": 1 + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-25 11:00:00" + } + }, + "type": "object" + }, + "ProductPagination": { + "description": "라라벨 LengthAwarePaginator 구조", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 123 + } + }, + "type": "object" + }, + "ProductCreateRequest": { + "required": [ + "code", + "name", + "category_id", + "product_type" + ], + "properties": { + "code": { + "type": "string", + "example": "PRD-001" + }, + "name": { + "type": "string", + "example": "스크린 모듈 KS001" + }, + "category_id": { + "type": "integer", + "example": 7 + }, + "product_type": { + "type": "string", + "example": "PRODUCT" + }, + "attributes": { + "type": "object", + "example": { + "color": "black" + }, + "nullable": true + }, + "description": { + "type": "string", + "example": null, + "nullable": true + }, + "is_sellable": { + "type": "integer", + "example": 1 + }, + "is_purchasable": { + "type": "integer", + "example": 0 + }, + "is_producible": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "ProductUpdateRequest": { + "properties": { + "code": { + "type": "string", + "example": "PRD-001" + }, + "name": { + "type": "string", + "example": "스크린 모듈 KS001" + }, + "category_id": { + "type": "integer", + "example": 7 + }, + "product_type": { + "type": "string", + "example": "PART" + }, + "attributes": { + "type": "object", + "example": { + "size": "XL" + }, + "nullable": true + }, + "description": { + "type": "string", + "example": "사양 변경", + "nullable": true + }, + "is_sellable": { + "type": "integer", + "example": 1 + }, + "is_purchasable": { + "type": "integer", + "example": 0 + }, + "is_producible": { + "type": "integer", + "example": 1 + }, + "is_active": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "BomItem": { + "required": [ + "id", + "ref_type", + "ref_id", + "quantity", + "sort_order" + ], + "properties": { + "id": { + "description": "BOM 스키마들", + "type": "integer", + "example": 11 + }, + "ref_type": { + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ], + "example": "PRODUCT" + }, + "ref_id": { + "type": "integer", + "example": 3 + }, + "code": { + "type": "string", + "example": "PRD-003", + "nullable": true + }, + "name": { + "type": "string", + "example": "모듈A", + "nullable": true + }, + "unit": { + "type": "string", + "example": "EA", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "float", + "example": 2 + }, + "sort_order": { + "type": "integer", + "example": 1 + }, + "is_default": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "BomItemBulkUpsertRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": null, + "nullable": true + }, + "ref_type": { + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ], + "example": "MATERIAL" + }, + "ref_id": { + "type": "integer", + "example": 5 + }, + "quantity": { + "type": "number", + "format": "float", + "example": 4 + }, + "sort_order": { + "type": "integer", + "example": 2 + }, + "is_default": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "BomItemUpdateRequest": { + "properties": { + "ref_type": { + "type": "string", + "enum": [ + "PRODUCT", + "MATERIAL" + ], + "example": "PRODUCT" + }, + "ref_id": { + "type": "integer", + "example": 9 + }, + "quantity": { + "type": "number", + "format": "float", + "example": 1.5 + }, + "sort_order": { + "type": "integer", + "example": 3 + }, + "is_default": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "BomReorderRequest": { + "type": "array", + "items": { + "required": [ + "id", + "sort_order" + ], + "properties": { + "id": { + "type": "integer", + "example": 11 + }, + "sort_order": { + "type": "integer", + "example": 1 + } + }, + "type": "object" + } + }, + "Purchase": { + "description": "매입 정보", + "properties": { + "id": { + "description": "매입 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "purchase_number": { + "description": "매입번호", + "type": "string", + "example": "PU202501150001" + }, + "purchase_date": { + "description": "매입일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "example": 100000 + }, + "total_amount": { + "description": "합계", + "type": "number", + "format": "float", + "example": 1100000 + }, + "description": { + "description": "적요", + "type": "string", + "example": "1월 매입", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "draft", + "confirmed" + ], + "example": "draft" + }, + "withdrawal_id": { + "description": "출금 연결 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "approval_id": { + "description": "연결된 품의서/지출결의서 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client": { + "description": "거래처 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "(주)공급사" + } + }, + "type": "object", + "nullable": true + }, + "approval": { + "description": "연결된 품의서/지출결의서 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "document_number": { + "type": "string", + "example": "AP202501150001" + }, + "title": { + "type": "string", + "example": "원자재 구매 품의" + }, + "form": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "품의서" + }, + "category": { + "type": "string", + "example": "proposal" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object", + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "PurchaseCreateRequest": { + "description": "매입 등록 요청", + "required": [ + "purchase_date", + "client_id", + "supply_amount", + "tax_amount", + "total_amount" + ], + "properties": { + "purchase_date": { + "description": "매입일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "example": 100000 + }, + "total_amount": { + "description": "합계", + "type": "number", + "format": "float", + "example": 1100000 + }, + "description": { + "description": "적요", + "type": "string", + "maxLength": 1000, + "example": "1월 매입", + "nullable": true + }, + "withdrawal_id": { + "description": "출금 연결 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "approval_id": { + "description": "연결할 품의서/지출결의서 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "PurchaseUpdateRequest": { + "description": "매입 수정 요청", + "properties": { + "purchase_date": { + "description": "매입일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "example": 100000 + }, + "total_amount": { + "description": "합계", + "type": "number", + "format": "float", + "example": 1100000 + }, + "description": { + "description": "적요", + "type": "string", + "maxLength": 1000, + "example": "1월 매입", + "nullable": true + }, + "withdrawal_id": { + "description": "출금 연결 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "approval_id": { + "description": "연결할 품의서/지출결의서 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "PurchaseSummary": { + "description": "매입 요약", + "properties": { + "total_supply_amount": { + "description": "총 공급가액", + "type": "number", + "format": "float", + "example": 10000000 + }, + "total_tax_amount": { + "description": "총 세액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "total_amount": { + "description": "총 합계", + "type": "number", + "format": "float", + "example": 11000000 + }, + "total_count": { + "description": "총 건수", + "type": "integer", + "example": 10 + }, + "by_status": { + "description": "상태별 합계", + "properties": { + "draft": { + "properties": { + "total": { + "type": "number", + "example": 5500000 + }, + "count": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "confirmed": { + "properties": { + "total": { + "type": "number", + "example": 5500000 + }, + "count": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "PurchaseDashboardDetail": { + "description": "매입 대시보드 상세 (CEO 대시보드 모달용)", + "properties": { + "summary": { + "description": "요약 정보", + "properties": { + "current_month_total": { + "description": "당월 매입 합계", + "type": "number", + "format": "float", + "example": 305000000 + }, + "previous_month_total": { + "description": "전월 매입 합계", + "type": "number", + "format": "float", + "example": 276000000 + }, + "change_rate": { + "description": "전월 대비 변화율 (%)", + "type": "number", + "format": "float", + "example": 10.5 + }, + "count": { + "description": "당월 매입 건수", + "type": "integer", + "example": 45 + } + }, + "type": "object" + }, + "monthly_trend": { + "description": "월별 추이 (최근 7개월)", + "type": "array", + "items": { + "properties": { + "month": { + "description": "월", + "type": "string", + "example": "2026-01" + }, + "amount": { + "description": "매입 합계", + "type": "number", + "format": "float", + "example": 280000000 + } + }, + "type": "object" + } + }, + "by_type": { + "description": "유형별 분포", + "type": "array", + "items": { + "properties": { + "type": { + "description": "유형 코드", + "type": "string", + "example": "raw_material" + }, + "label": { + "description": "유형 라벨", + "type": "string", + "example": "원재료매입" + }, + "amount": { + "description": "합계", + "type": "number", + "format": "float", + "example": 180000000 + }, + "ratio": { + "description": "비율 (%)", + "type": "number", + "format": "float", + "example": 59 + } + }, + "type": "object" + } + }, + "items": { + "description": "일별 매입 내역", + "type": "array", + "items": { + "properties": { + "id": { + "description": "매입 ID", + "type": "integer", + "example": 1 + }, + "date": { + "description": "매입일", + "type": "string", + "format": "date", + "example": "2026-01-15" + }, + "vendor_name": { + "description": "거래처명", + "type": "string", + "example": "대한철강" + }, + "amount": { + "description": "매입금액", + "type": "number", + "format": "float", + "example": 15000000 + }, + "type": { + "description": "매입유형 코드", + "type": "string", + "example": "raw_material" + }, + "type_label": { + "description": "매입유형 라벨", + "type": "string", + "example": "원재료매입" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "PushDeviceToken": { + "description": "푸시 디바이스 토큰", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "integer", + "example": 5 + }, + "token": { + "type": "string", + "example": "dGhpcyBpcyBhIHNhbXBsZSBGQ00gdG9rZW4..." + }, + "platform": { + "type": "string", + "enum": [ + "ios", + "android", + "web" + ], + "example": "android" + }, + "device_name": { + "type": "string", + "example": "Samsung Galaxy S24", + "nullable": true + }, + "app_version": { + "type": "string", + "example": "1.0.0", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "last_used_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:30:00" + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:30:00" + } + }, + "type": "object" + }, + "PushNotificationSetting": { + "description": "푸시 알림 설정", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "integer", + "example": 5 + }, + "notification_type": { + "type": "string", + "enum": [ + "deposit", + "withdrawal", + "order", + "approval", + "attendance", + "notice", + "system" + ], + "example": "deposit" + }, + "is_enabled": { + "type": "boolean", + "example": true + }, + "sound": { + "type": "string", + "enum": [ + "default.wav", + "deposit.wav", + "withdrawal.wav", + "order.wav", + "approval.wav", + "urgent.wav" + ], + "example": "deposit.wav" + }, + "vibrate": { + "type": "boolean", + "example": true + }, + "show_preview": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-18 10:30:00" + } + }, + "type": "object" + }, + "RegisterTokenRequest": { + "required": [ + "token", + "platform" + ], + "properties": { + "token": { + "description": "FCM 토큰", + "type": "string", + "minLength": 10, + "example": "dGhpcyBpcyBhIHNhbXBsZSBGQ00gdG9rZW4..." + }, + "platform": { + "description": "디바이스 플랫폼", + "type": "string", + "enum": [ + "ios", + "android", + "web" + ], + "example": "android" + }, + "device_name": { + "description": "디바이스명", + "type": "string", + "maxLength": 255, + "example": "Samsung Galaxy S24", + "nullable": true + }, + "app_version": { + "description": "앱 버전", + "type": "string", + "maxLength": 50, + "example": "1.0.0", + "nullable": true + } + }, + "type": "object" + }, + "UnregisterTokenRequest": { + "required": [ + "token" + ], + "properties": { + "token": { + "description": "해제할 FCM 토큰", + "type": "string", + "example": "dGhpcyBpcyBhIHNhbXBsZSBGQ00gdG9rZW4..." + } + }, + "type": "object" + }, + "UpdatePushSettingsRequest": { + "required": [ + "settings" + ], + "properties": { + "settings": { + "description": "알림 설정 배열", + "type": "array", + "items": { + "required": [ + "notification_type", + "is_enabled" + ], + "properties": { + "notification_type": { + "type": "string", + "enum": [ + "deposit", + "withdrawal", + "order", + "approval", + "attendance", + "notice", + "system" + ], + "example": "deposit" + }, + "is_enabled": { + "type": "boolean", + "example": true + }, + "sound": { + "type": "string", + "enum": [ + "default.wav", + "deposit.wav", + "withdrawal.wav", + "order.wav", + "approval.wav", + "urgent.wav" + ], + "example": "deposit.wav", + "nullable": true + }, + "vibrate": { + "type": "boolean", + "example": true, + "nullable": true + }, + "show_preview": { + "type": "boolean", + "example": true, + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "NotificationTypesResponse": { + "properties": { + "types": { + "description": "지원하는 알림 유형 목록", + "type": "array", + "items": { + "type": "string", + "example": "deposit" + } + }, + "sounds": { + "description": "지원하는 알림음 목록", + "type": "array", + "items": { + "type": "string", + "example": "deposit.wav" + } + } + }, + "type": "object" + }, + "Quote": { + "required": [ + "id", + "quote_number" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "quote_number": { + "description": "견적번호", + "type": "string", + "example": "KD-SC-251204-01" + }, + "registration_date": { + "description": "등록일", + "type": "string", + "format": "date", + "example": "2025-12-04" + }, + "receipt_date": { + "description": "접수일", + "type": "string", + "format": "date", + "example": "2025-12-05", + "nullable": true + }, + "author": { + "description": "작성자", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "description": "발주처명", + "type": "string", + "example": "ABC건설", + "nullable": true + }, + "manager": { + "description": "담당자", + "type": "string", + "example": "김담당", + "nullable": true + }, + "contact": { + "description": "연락처", + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "site_id": { + "description": "현장 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "site_name": { + "description": "현장명", + "type": "string", + "example": "강남현장", + "nullable": true + }, + "site_code": { + "description": "현장코드", + "type": "string", + "example": "SITE-001", + "nullable": true + }, + "product_category": { + "description": "제품 카테고리", + "type": "string", + "enum": [ + "SCREEN", + "STEEL" + ], + "example": "SCREEN" + }, + "product_id": { + "description": "제품 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "product_code": { + "description": "제품코드", + "type": "string", + "example": "SCR-001", + "nullable": true + }, + "product_name": { + "description": "제품명", + "type": "string", + "example": "전동스크린", + "nullable": true + }, + "open_size_width": { + "description": "개구부 폭(mm)", + "type": "number", + "format": "float", + "example": 3000, + "nullable": true + }, + "open_size_height": { + "description": "개구부 높이(mm)", + "type": "number", + "format": "float", + "example": 2500, + "nullable": true + }, + "quantity": { + "description": "수량", + "type": "integer", + "example": 1 + }, + "unit_symbol": { + "description": "단위", + "type": "string", + "example": "EA", + "nullable": true + }, + "floors": { + "description": "층수", + "type": "string", + "example": "1F~3F", + "nullable": true + }, + "material_cost": { + "description": "자재비", + "type": "number", + "format": "float", + "example": 500000 + }, + "labor_cost": { + "description": "인건비", + "type": "number", + "format": "float", + "example": 100000 + }, + "install_cost": { + "description": "설치비", + "type": "number", + "format": "float", + "example": 50000 + }, + "subtotal": { + "description": "소계", + "type": "number", + "format": "float", + "example": 650000 + }, + "discount_rate": { + "description": "할인율(%)", + "type": "number", + "format": "float", + "example": 10 + }, + "discount_amount": { + "description": "할인금액", + "type": "number", + "format": "float", + "example": 65000 + }, + "total_amount": { + "description": "합계금액", + "type": "number", + "format": "float", + "example": 585000 + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "draft", + "sent", + "approved", + "rejected", + "finalized", + "converted" + ], + "example": "draft" + }, + "current_revision": { + "description": "현재 리비전", + "type": "integer", + "example": 0 + }, + "is_final": { + "description": "확정 여부", + "type": "boolean", + "example": false + }, + "finalized_at": { + "description": "확정일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "finalized_by": { + "description": "확정자 ID", + "type": "integer", + "nullable": true + }, + "completion_date": { + "description": "완료예정일", + "type": "string", + "format": "date", + "nullable": true + }, + "remarks": { + "description": "비고", + "type": "string", + "nullable": true + }, + "memo": { + "description": "메모", + "type": "string", + "nullable": true + }, + "notes": { + "description": "참고사항", + "type": "string", + "nullable": true + }, + "calculation_inputs": { + "description": "자동산출 입력값", + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-04 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-12-04 10:00:00" + }, + "items": { + "description": "견적 품목", + "type": "array", + "items": { + "$ref": "#/components/schemas/QuoteItem" + } + } + }, + "type": "object" + }, + "QuoteItem": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "quote_id": { + "type": "integer", + "example": 1 + }, + "item_id": { + "description": "품목 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "item_code": { + "description": "품목코드", + "type": "string", + "example": "SCR-FABRIC-001" + }, + "item_name": { + "description": "품목명", + "type": "string", + "example": "스크린 원단" + }, + "specification": { + "description": "규격", + "type": "string", + "example": "3100 x 2650 mm", + "nullable": true + }, + "unit": { + "description": "단위", + "type": "string", + "example": "m²" + }, + "base_quantity": { + "description": "기본수량", + "type": "number", + "format": "float", + "example": 1 + }, + "calculated_quantity": { + "description": "산출수량", + "type": "number", + "format": "float", + "example": 8.215 + }, + "unit_price": { + "description": "단가", + "type": "number", + "format": "float", + "example": 25000 + }, + "total_price": { + "description": "금액", + "type": "number", + "format": "float", + "example": 205375 + }, + "formula": { + "description": "수량 수식", + "type": "string", + "example": "AREA * QTY", + "nullable": true + }, + "formula_result": { + "description": "수식 결과", + "type": "string", + "nullable": true + }, + "formula_source": { + "description": "수식 출처", + "type": "string", + "nullable": true + }, + "formula_category": { + "description": "비용 카테고리", + "type": "string", + "example": "material", + "nullable": true + }, + "note": { + "description": "비고", + "type": "string", + "nullable": true + }, + "sort_order": { + "description": "정렬순서", + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "QuotePagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Quote" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/quotes?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 3 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/quotes?page=3" + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/quotes?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/quotes" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 50 + } + }, + "type": "object" + }, + "QuoteCreateRequest": { + "properties": { + "quote_number": { + "description": "견적번호(미입력시 자동생성)", + "type": "string", + "maxLength": 50, + "nullable": true + }, + "registration_date": { + "type": "string", + "format": "date", + "example": "2025-12-04", + "nullable": true + }, + "receipt_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "author": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "client_id": { + "type": "integer", + "nullable": true + }, + "client_name": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "manager": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "contact": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "site_id": { + "type": "integer", + "nullable": true + }, + "site_name": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "site_code": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "product_category": { + "type": "string", + "enum": [ + "SCREEN", + "STEEL" + ], + "nullable": true + }, + "product_id": { + "type": "integer", + "nullable": true + }, + "product_code": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "product_name": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "open_size_width": { + "type": "number", + "format": "float", + "nullable": true + }, + "open_size_height": { + "type": "number", + "format": "float", + "nullable": true + }, + "quantity": { + "type": "integer", + "minimum": 1, + "nullable": true + }, + "unit_symbol": { + "type": "string", + "maxLength": 10, + "nullable": true + }, + "floors": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "material_cost": { + "type": "number", + "format": "float", + "nullable": true + }, + "labor_cost": { + "type": "number", + "format": "float", + "nullable": true + }, + "install_cost": { + "type": "number", + "format": "float", + "nullable": true + }, + "discount_rate": { + "type": "number", + "format": "float", + "maximum": 100, + "minimum": 0, + "nullable": true + }, + "total_amount": { + "type": "number", + "format": "float", + "nullable": true + }, + "completion_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "remarks": { + "type": "string", + "maxLength": 500, + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "notes": { + "type": "string", + "nullable": true + }, + "calculation_inputs": { + "type": "object", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QuoteItemRequest" + }, + "nullable": true + } + }, + "type": "object" + }, + "QuoteUpdateRequest": { + "properties": { + "receipt_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "author": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "client_id": { + "type": "integer", + "nullable": true + }, + "client_name": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "manager": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "contact": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "site_id": { + "type": "integer", + "nullable": true + }, + "site_name": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "site_code": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "product_category": { + "type": "string", + "enum": [ + "SCREEN", + "STEEL" + ], + "nullable": true + }, + "product_id": { + "type": "integer", + "nullable": true + }, + "product_code": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "product_name": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "open_size_width": { + "type": "number", + "format": "float", + "nullable": true + }, + "open_size_height": { + "type": "number", + "format": "float", + "nullable": true + }, + "quantity": { + "type": "integer", + "minimum": 1, + "nullable": true + }, + "unit_symbol": { + "type": "string", + "maxLength": 10, + "nullable": true + }, + "floors": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "material_cost": { + "type": "number", + "format": "float", + "nullable": true + }, + "labor_cost": { + "type": "number", + "format": "float", + "nullable": true + }, + "install_cost": { + "type": "number", + "format": "float", + "nullable": true + }, + "discount_rate": { + "type": "number", + "format": "float", + "maximum": 100, + "minimum": 0, + "nullable": true + }, + "total_amount": { + "type": "number", + "format": "float", + "nullable": true + }, + "completion_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "remarks": { + "type": "string", + "maxLength": 500, + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "notes": { + "type": "string", + "nullable": true + }, + "calculation_inputs": { + "type": "object", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QuoteItemRequest" + }, + "nullable": true + } + }, + "type": "object" + }, + "QuoteItemRequest": { + "properties": { + "item_id": { + "type": "integer", + "nullable": true + }, + "item_code": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "item_name": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "specification": { + "type": "string", + "maxLength": 200, + "nullable": true + }, + "unit": { + "type": "string", + "maxLength": 20, + "nullable": true + }, + "base_quantity": { + "type": "number", + "format": "float", + "nullable": true + }, + "calculated_quantity": { + "type": "number", + "format": "float", + "nullable": true + }, + "unit_price": { + "type": "number", + "format": "float", + "nullable": true + }, + "total_price": { + "type": "number", + "format": "float", + "nullable": true + }, + "formula": { + "type": "string", + "maxLength": 500, + "nullable": true + }, + "formula_result": { + "type": "string", + "nullable": true + }, + "formula_source": { + "type": "string", + "nullable": true + }, + "formula_category": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "note": { + "type": "string", + "maxLength": 500, + "nullable": true + }, + "sort_order": { + "type": "integer", + "nullable": true + } + }, + "type": "object" + }, + "QuoteCalculateRequest": { + "properties": { + "product_category": { + "description": "제품 카테고리", + "type": "string", + "enum": [ + "SCREEN", + "STEEL" + ], + "nullable": true + }, + "W0": { + "description": "개구부 폭(mm)", + "type": "number", + "format": "float", + "example": 3000 + }, + "H0": { + "description": "개구부 높이(mm)", + "type": "number", + "format": "float", + "example": 2500 + }, + "QTY": { + "description": "수량", + "type": "integer", + "example": 1 + }, + "INSTALL_TYPE": { + "description": "설치유형(스크린)", + "type": "string", + "enum": [ + "wall", + "ceiling", + "floor" + ], + "nullable": true + }, + "MOTOR_TYPE": { + "description": "모터유형(스크린)", + "type": "string", + "enum": [ + "standard", + "heavy" + ], + "nullable": true + }, + "CONTROL_TYPE": { + "description": "제어방식(스크린)", + "type": "string", + "enum": [ + "switch", + "remote", + "smart" + ], + "nullable": true + }, + "MATERIAL": { + "description": "재질(철재)", + "type": "string", + "enum": [ + "ss304", + "ss316", + "galvanized" + ], + "nullable": true + }, + "THICKNESS": { + "description": "두께(철재)", + "type": "number", + "format": "float", + "nullable": true + }, + "FINISH": { + "description": "표면처리(철재)", + "type": "string", + "enum": [ + "hairline", + "mirror", + "matte" + ], + "nullable": true + }, + "WELDING": { + "description": "용접방식(철재)", + "type": "string", + "enum": [ + "tig", + "mig", + "spot" + ], + "nullable": true + } + }, + "type": "object" + }, + "QuoteCalculationResult": { + "properties": { + "inputs": { + "description": "입력 파라미터", + "type": "object" + }, + "outputs": { + "description": "산출값 (W1, H1, AREA, WEIGHT 등)", + "type": "object" + }, + "items": { + "description": "산출된 품목", + "type": "array", + "items": { + "$ref": "#/components/schemas/QuoteItem" + } + }, + "costs": { + "properties": { + "material_cost": { + "type": "number", + "format": "float" + }, + "labor_cost": { + "type": "number", + "format": "float" + }, + "install_cost": { + "type": "number", + "format": "float" + }, + "subtotal": { + "type": "number", + "format": "float" + } + }, + "type": "object" + }, + "errors": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "type": "object" + }, + "QuoteSendEmailRequest": { + "properties": { + "email": { + "description": "수신자 이메일", + "type": "string", + "format": "email", + "nullable": true + }, + "name": { + "description": "수신자명", + "type": "string", + "maxLength": 100, + "nullable": true + }, + "subject": { + "description": "제목", + "type": "string", + "maxLength": 200, + "nullable": true + }, + "message": { + "description": "본문", + "type": "string", + "maxLength": 2000, + "nullable": true + }, + "cc": { + "description": "참조", + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "nullable": true + }, + "attach_pdf": { + "description": "PDF 첨부 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "QuoteSendKakaoRequest": { + "properties": { + "phone": { + "description": "수신자 전화번호", + "type": "string", + "maxLength": 20, + "nullable": true + }, + "name": { + "description": "수신자명", + "type": "string", + "maxLength": 100, + "nullable": true + }, + "template_code": { + "description": "템플릿 코드", + "type": "string", + "maxLength": 50, + "nullable": true + }, + "view_url": { + "description": "조회 URL", + "type": "string", + "format": "uri", + "nullable": true + } + }, + "type": "object" + }, + "QuoteNumberPreview": { + "properties": { + "quote_number": { + "type": "string", + "example": "KD-SC-251204-01" + }, + "product_category": { + "type": "string", + "example": "SCREEN" + }, + "generated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "QuoteBomCalculateRequest": { + "required": [ + "finished_goods_code", + "W0", + "H0" + ], + "properties": { + "finished_goods_code": { + "description": "완제품 코드", + "type": "string", + "example": "SC-1000" + }, + "W0": { + "description": "개구부 폭(mm)", + "type": "number", + "format": "float", + "maximum": 20000, + "minimum": 100, + "example": 3000 + }, + "H0": { + "description": "개구부 높이(mm)", + "type": "number", + "format": "float", + "maximum": 20000, + "minimum": 100, + "example": 2500 + }, + "QTY": { + "description": "수량", + "type": "integer", + "minimum": 1, + "example": 1 + }, + "PC": { + "description": "제품 카테고리", + "type": "string", + "enum": [ + "SCREEN", + "STEEL" + ], + "example": "SCREEN" + }, + "GT": { + "description": "가이드레일 타입", + "type": "string", + "enum": [ + "wall", + "ceiling", + "floor" + ], + "example": "wall" + }, + "MP": { + "description": "모터 전원", + "type": "string", + "enum": [ + "single", + "three" + ], + "example": "single" + }, + "CT": { + "description": "컨트롤러", + "type": "string", + "enum": [ + "basic", + "smart", + "premium" + ], + "example": "basic" + }, + "WS": { + "description": "날개 크기", + "type": "number", + "format": "float", + "example": 50 + }, + "INSP": { + "description": "검사비", + "type": "number", + "format": "float", + "example": 50000 + }, + "debug": { + "description": "디버그 모드 (10단계 디버깅 정보 포함)", + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "QuoteBomBulkCalculateRequest": { + "description": "다건 BOM 기반 자동산출 요청. React QuoteFormItem 필드명(camelCase)과 API 변수명(약어) 모두 지원합니다.", + "required": [ + "items" + ], + "properties": { + "items": { + "description": "견적 품목 배열", + "type": "array", + "items": { + "$ref": "#/components/schemas/QuoteBomBulkItemInput" + }, + "minItems": 1 + }, + "debug": { + "description": "디버그 모드 (10단계 디버깅 정보 포함)", + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "QuoteBomBulkItemInput": { + "description": "개별 품목 입력. React QuoteFormItem 필드명(camelCase)과 API 변수명(약어) 모두 지원합니다.", + "required": [ + "finished_goods_code" + ], + "properties": { + "finished_goods_code": { + "description": "완제품 코드 (items.code where item_type='FG')", + "type": "string", + "example": "SC-1000" + }, + "openWidth": { + "description": "개구부 폭(mm) - React 필드명", + "type": "number", + "format": "float", + "example": 3000 + }, + "openHeight": { + "description": "개구부 높이(mm) - React 필드명", + "type": "number", + "format": "float", + "example": 2500 + }, + "quantity": { + "description": "수량 - React 필드명", + "type": "integer", + "example": 1 + }, + "productCategory": { + "description": "제품 카테고리 - React 필드명", + "type": "string", + "example": "SCREEN" + }, + "guideRailType": { + "description": "가이드레일 타입 - React 필드명", + "type": "string", + "example": "wall" + }, + "motorPower": { + "description": "모터 전원 - React 필드명", + "type": "string", + "example": "single" + }, + "controller": { + "description": "컨트롤러 - React 필드명", + "type": "string", + "example": "basic" + }, + "wingSize": { + "description": "날개 크기 - React 필드명", + "type": "number", + "format": "float", + "example": 50 + }, + "inspectionFee": { + "description": "검사비 - React 필드명", + "type": "number", + "format": "float", + "example": 50000 + }, + "W0": { + "description": "개구부 폭(mm) - API 변수명", + "type": "number", + "format": "float", + "example": 3000 + }, + "H0": { + "description": "개구부 높이(mm) - API 변수명", + "type": "number", + "format": "float", + "example": 2500 + }, + "QTY": { + "description": "수량 - API 변수명", + "type": "integer", + "example": 1 + }, + "PC": { + "description": "제품 카테고리 - API 변수명", + "type": "string", + "example": "SCREEN" + }, + "GT": { + "description": "가이드레일 타입 - API 변수명", + "type": "string", + "example": "wall" + }, + "MP": { + "description": "모터 전원 - API 변수명", + "type": "string", + "example": "single" + }, + "CT": { + "description": "컨트롤러 - API 변수명", + "type": "string", + "example": "basic" + }, + "WS": { + "description": "날개 크기 - API 변수명", + "type": "number", + "format": "float", + "example": 50 + }, + "INSP": { + "description": "검사비 - API 변수명", + "type": "number", + "format": "float", + "example": 50000 + } + }, + "type": "object" + }, + "QuoteBomBulkCalculationResult": { + "properties": { + "success": { + "description": "전체 성공 여부 (실패 건이 없으면 true)", + "type": "boolean", + "example": true + }, + "summary": { + "description": "처리 요약", + "properties": { + "total_count": { + "description": "전체 품목 수", + "type": "integer", + "example": 3 + }, + "success_count": { + "description": "성공 건수", + "type": "integer", + "example": 2 + }, + "fail_count": { + "description": "실패 건수", + "type": "integer", + "example": 1 + }, + "grand_total": { + "description": "성공한 품목 총계", + "type": "number", + "format": "float", + "example": 1500000 + } + }, + "type": "object" + }, + "items": { + "description": "품목별 산출 결과", + "type": "array", + "items": { + "properties": { + "index": { + "description": "요청 배열에서의 인덱스", + "type": "integer", + "example": 0 + }, + "finished_goods_code": { + "type": "string", + "example": "SC-1000" + }, + "inputs": { + "description": "정규화된 입력 변수", + "type": "object" + }, + "result": { + "$ref": "#/components/schemas/QuoteBomCalculationResult" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "QuoteBomCalculationResult": { + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "finished_goods": { + "description": "완제품 정보", + "properties": { + "code": { + "type": "string", + "example": "SC-1000" + }, + "name": { + "type": "string", + "example": "전동스크린 1000형" + } + }, + "type": "object" + }, + "variables": { + "description": "계산 변수 (W0, H0, W1, H1, M, K 등)", + "type": "object" + }, + "items": { + "description": "산출된 품목", + "type": "array", + "items": { + "$ref": "#/components/schemas/QuoteItem" + } + }, + "grouped_items": { + "description": "카테고리별 품목 그룹", + "type": "object" + }, + "subtotals": { + "description": "카테고리별 소계", + "properties": { + "material": { + "type": "number", + "format": "float" + }, + "labor": { + "type": "number", + "format": "float" + }, + "install": { + "type": "number", + "format": "float" + } + }, + "type": "object" + }, + "grand_total": { + "description": "총계", + "type": "number", + "format": "float" + }, + "debug_steps": { + "description": "디버그 모드시 10단계 디버깅 정보", + "type": "array", + "items": { + "type": "object" + }, + "nullable": true + } + }, + "type": "object" + }, + "MonthlyAmount": { + "description": "월별 금액", + "properties": { + "month1": { + "description": "1월", + "type": "number", + "format": "float", + "example": 1000000 + }, + "month2": { + "description": "2월", + "type": "number", + "format": "float", + "example": 0 + }, + "month3": { + "description": "3월", + "type": "number", + "format": "float", + "example": 0 + }, + "month4": { + "description": "4월", + "type": "number", + "format": "float", + "example": 0 + }, + "month5": { + "description": "5월", + "type": "number", + "format": "float", + "example": 0 + }, + "month6": { + "description": "6월", + "type": "number", + "format": "float", + "example": 0 + }, + "month7": { + "description": "7월", + "type": "number", + "format": "float", + "example": 0 + }, + "month8": { + "description": "8월", + "type": "number", + "format": "float", + "example": 0 + }, + "month9": { + "description": "9월", + "type": "number", + "format": "float", + "example": 0 + }, + "month10": { + "description": "10월", + "type": "number", + "format": "float", + "example": 0 + }, + "month11": { + "description": "11월", + "type": "number", + "format": "float", + "example": 0 + }, + "month12": { + "description": "12월", + "type": "number", + "format": "float", + "example": 500000 + }, + "total": { + "description": "합계", + "type": "number", + "format": "float", + "example": 1500000 + } + }, + "type": "object" + }, + "CategoryAmount": { + "description": "카테고리별 금액", + "properties": { + "category": { + "description": "구분", + "type": "string", + "enum": [ + "sales", + "deposit", + "bill", + "receivable", + "memo" + ], + "example": "sales" + }, + "amounts": { + "$ref": "#/components/schemas/MonthlyAmount" + } + }, + "type": "object" + }, + "VendorReceivables": { + "description": "거래처별 채권 현황", + "properties": { + "id": { + "description": "거래처 ID (string)", + "type": "string", + "example": "1" + }, + "vendor_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "vendor_name": { + "description": "거래처명", + "type": "string", + "example": "(주)삼성전자" + }, + "is_overdue": { + "description": "연체 여부", + "type": "boolean", + "example": true + }, + "overdue_months": { + "description": "연체 월 목록", + "type": "array", + "items": { + "type": "integer", + "example": 1 + } + }, + "categories": { + "description": "카테고리별 데이터", + "type": "array", + "items": { + "$ref": "#/components/schemas/CategoryAmount" + } + } + }, + "type": "object" + }, + "ReceivablesSummary": { + "description": "채권 현황 요약 통계", + "properties": { + "total_sales": { + "description": "총 매출", + "type": "number", + "format": "float", + "example": 100000000 + }, + "total_deposits": { + "description": "총 입금", + "type": "number", + "format": "float", + "example": 80000000 + }, + "total_bills": { + "description": "총 어음", + "type": "number", + "format": "float", + "example": 5000000 + }, + "total_receivables": { + "description": "총 미수금", + "type": "number", + "format": "float", + "example": 15000000 + }, + "vendor_count": { + "description": "거래처 수", + "type": "integer", + "example": 50 + }, + "overdue_vendor_count": { + "description": "연체 거래처 수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "Receiving": { + "description": "입고 정보", + "properties": { + "id": { + "description": "입고 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "receiving_number": { + "description": "입고번호", + "type": "string", + "example": "RV202512260001" + }, + "order_no": { + "description": "발주번호", + "type": "string", + "example": "PO-2025-001", + "nullable": true + }, + "order_date": { + "description": "발주일자", + "type": "string", + "format": "date", + "example": "2025-12-20", + "nullable": true + }, + "item_id": { + "description": "품목 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "item_code": { + "description": "품목코드", + "type": "string", + "example": "ITEM-001" + }, + "item_name": { + "description": "품목명", + "type": "string", + "example": "원재료 A" + }, + "specification": { + "description": "규격", + "type": "string", + "example": "100x100", + "nullable": true + }, + "supplier": { + "description": "공급업체", + "type": "string", + "example": "(주)공급사" + }, + "order_qty": { + "description": "발주수량", + "type": "number", + "format": "float", + "example": 100 + }, + "order_unit": { + "description": "발주단위", + "type": "string", + "example": "EA" + }, + "due_date": { + "description": "납기일", + "type": "string", + "format": "date", + "example": "2025-12-26", + "nullable": true + }, + "receiving_qty": { + "description": "입고수량", + "type": "number", + "format": "float", + "example": 100, + "nullable": true + }, + "receiving_date": { + "description": "입고일자", + "type": "string", + "format": "date", + "example": "2025-12-26", + "nullable": true + }, + "lot_no": { + "description": "입고 LOT번호", + "type": "string", + "example": "251226-01", + "nullable": true + }, + "supplier_lot": { + "description": "공급업체 LOT", + "type": "string", + "example": "SUP-LOT-001", + "nullable": true + }, + "receiving_location": { + "description": "입고위치", + "type": "string", + "example": "A-01-01", + "nullable": true + }, + "receiving_manager": { + "description": "입고담당", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "order_completed", + "shipping", + "inspection_pending", + "receiving_pending", + "completed" + ], + "example": "receiving_pending" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "입고대기" + }, + "remark": { + "description": "비고", + "type": "string", + "example": "비고 내용", + "nullable": true + }, + "creator": { + "description": "생성자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "관리자" + } + }, + "type": "object", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "ReceivingStats": { + "description": "입고 통계", + "properties": { + "receiving_pending_count": { + "description": "입고대기 건수", + "type": "integer", + "example": 5 + }, + "shipping_count": { + "description": "배송중 건수", + "type": "integer", + "example": 3 + }, + "inspection_pending_count": { + "description": "검사대기 건수", + "type": "integer", + "example": 2 + }, + "today_receiving_count": { + "description": "금일 입고 건수", + "type": "integer", + "example": 10 + } + }, + "type": "object" + }, + "ReceivingCreateRequest": { + "description": "입고 등록 요청", + "required": [ + "item_code", + "item_name", + "supplier", + "order_qty" + ], + "properties": { + "order_no": { + "description": "발주번호", + "type": "string", + "maxLength": 30, + "example": "PO-2025-001", + "nullable": true + }, + "order_date": { + "description": "발주일자", + "type": "string", + "format": "date", + "example": "2025-12-20", + "nullable": true + }, + "item_id": { + "description": "품목 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "item_code": { + "description": "품목코드", + "type": "string", + "maxLength": 50, + "example": "ITEM-001" + }, + "item_name": { + "description": "품목명", + "type": "string", + "maxLength": 200, + "example": "원재료 A" + }, + "specification": { + "description": "규격", + "type": "string", + "maxLength": 200, + "example": "100x100", + "nullable": true + }, + "supplier": { + "description": "공급업체", + "type": "string", + "maxLength": 100, + "example": "(주)공급사" + }, + "order_qty": { + "description": "발주수량", + "type": "number", + "format": "float", + "example": 100 + }, + "order_unit": { + "description": "발주단위", + "type": "string", + "maxLength": 20, + "example": "EA" + }, + "due_date": { + "description": "납기일", + "type": "string", + "format": "date", + "example": "2025-12-26", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "order_completed", + "shipping", + "inspection_pending", + "receiving_pending" + ], + "example": "order_completed" + }, + "remark": { + "description": "비고", + "type": "string", + "maxLength": 1000, + "example": "비고 내용", + "nullable": true + } + }, + "type": "object" + }, + "ReceivingUpdateRequest": { + "description": "입고 수정 요청", + "properties": { + "order_no": { + "description": "발주번호", + "type": "string", + "maxLength": 30, + "example": "PO-2025-001", + "nullable": true + }, + "order_date": { + "description": "발주일자", + "type": "string", + "format": "date", + "example": "2025-12-20", + "nullable": true + }, + "item_code": { + "description": "품목코드", + "type": "string", + "maxLength": 50, + "example": "ITEM-001" + }, + "item_name": { + "description": "품목명", + "type": "string", + "maxLength": 200, + "example": "원재료 A" + }, + "specification": { + "description": "규격", + "type": "string", + "maxLength": 200, + "example": "100x100", + "nullable": true + }, + "supplier": { + "description": "공급업체", + "type": "string", + "maxLength": 100, + "example": "(주)공급사" + }, + "order_qty": { + "description": "발주수량", + "type": "number", + "format": "float", + "example": 100 + }, + "order_unit": { + "description": "발주단위", + "type": "string", + "maxLength": 20, + "example": "EA" + }, + "due_date": { + "description": "납기일", + "type": "string", + "format": "date", + "example": "2025-12-26", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "order_completed", + "shipping", + "inspection_pending", + "receiving_pending" + ], + "example": "shipping" + }, + "remark": { + "description": "비고", + "type": "string", + "maxLength": 1000, + "example": "비고 내용", + "nullable": true + } + }, + "type": "object" + }, + "ReceivingProcessRequest": { + "description": "입고처리 요청", + "required": [ + "receiving_qty", + "receiving_location" + ], + "properties": { + "receiving_qty": { + "description": "입고수량", + "type": "number", + "format": "float", + "example": 100 + }, + "receiving_date": { + "description": "입고일자 (미입력시 오늘)", + "type": "string", + "format": "date", + "example": "2025-12-26", + "nullable": true + }, + "lot_no": { + "description": "LOT번호 (미입력시 자동생성)", + "type": "string", + "maxLength": 50, + "example": "251226-01", + "nullable": true + }, + "supplier_lot": { + "description": "공급업체 LOT", + "type": "string", + "maxLength": 50, + "example": "SUP-LOT-001", + "nullable": true + }, + "receiving_location": { + "description": "입고위치", + "type": "string", + "maxLength": 100, + "example": "A-01-01" + }, + "receiving_manager": { + "description": "입고담당", + "type": "string", + "maxLength": 50, + "example": "홍길동", + "nullable": true + }, + "remark": { + "description": "비고", + "type": "string", + "maxLength": 1000, + "example": "비고 내용", + "nullable": true + } + }, + "type": "object" + }, + "DailyReport": { + "description": "일일 일보", + "properties": { + "date": { + "description": "기준일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "previous_balance": { + "description": "전일 잔액", + "type": "number", + "format": "float", + "example": 10000000 + }, + "daily_deposit": { + "description": "당일 입금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "daily_withdrawal": { + "description": "당일 출금액", + "type": "number", + "format": "float", + "example": 3000000 + }, + "current_balance": { + "description": "당일 잔액", + "type": "number", + "format": "float", + "example": 12000000 + }, + "details": { + "description": "상세 내역", + "type": "array", + "items": { + "properties": { + "type": { + "description": "유형", + "type": "string", + "enum": [ + "deposit", + "withdrawal" + ] + }, + "type_label": { + "description": "유형 라벨", + "type": "string", + "example": "입금" + }, + "client_name": { + "description": "거래처명", + "type": "string", + "example": "(주)테스트" + }, + "account_code": { + "description": "계정과목", + "type": "string", + "example": "401" + }, + "deposit_amount": { + "description": "입금액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "withdrawal_amount": { + "description": "출금액", + "type": "number", + "format": "float", + "example": 0 + }, + "description": { + "description": "적요", + "type": "string", + "example": "1월 매출 입금" + }, + "payment_method": { + "description": "결제수단", + "type": "string", + "example": "transfer" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "ExpenseEstimate": { + "description": "지출 예상 내역서", + "properties": { + "year_month": { + "description": "기준 연월", + "type": "string", + "example": "2025-01" + }, + "total_estimate": { + "description": "예상 지출 합계", + "type": "number", + "format": "float", + "example": 15000000 + }, + "account_balance": { + "description": "계좌 잔액", + "type": "number", + "format": "float", + "example": 20000000 + }, + "expected_balance": { + "description": "예상 잔액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "items": { + "description": "지출 예상 내역", + "type": "array", + "items": { + "properties": { + "id": { + "description": "매입 ID", + "type": "integer", + "example": 1 + }, + "expected_date": { + "description": "예상 지급일", + "type": "string", + "format": "date", + "example": "2025-01-20" + }, + "item_name": { + "description": "품목", + "type": "string", + "example": "원자재 구매" + }, + "amount": { + "description": "지출금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "client_name": { + "description": "거래처", + "type": "string", + "example": "(주)공급사" + }, + "account_name": { + "description": "계좌", + "type": "string", + "example": "법인통장" + } + }, + "type": "object" + } + }, + "monthly_summary": { + "description": "월별 합계", + "properties": { + "by_month": { + "type": "array", + "items": { + "properties": { + "month": { + "description": "월", + "type": "string", + "example": "2025/01" + }, + "total": { + "description": "합계", + "type": "number", + "format": "float", + "example": 5000000 + } + }, + "type": "object" + } + }, + "total_expense": { + "description": "지출 합계", + "type": "number", + "format": "float", + "example": 15000000 + }, + "account_balance": { + "description": "계좌 잔액", + "type": "number", + "format": "float", + "example": 20000000 + }, + "final_difference": { + "description": "최종 차액", + "type": "number", + "format": "float", + "example": 5000000 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Role": { + "description": "역할 상세", + "required": [ + "id", + "name", + "guard_name" + ], + "properties": { + "id": { + "type": "integer", + "example": 3 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "menu-manager" + }, + "description": { + "type": "string", + "example": "메뉴 관리 역할", + "nullable": true + }, + "guard_name": { + "type": "string", + "example": "api" + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-16 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-16 10:00:00" + } + }, + "type": "object" + }, + "RoleBrief": { + "description": "역할 요약", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "example": 3 + }, + "name": { + "type": "string", + "example": "readonly" + }, + "description": { + "type": "string", + "example": "읽기 전용", + "nullable": true + }, + "guard_name": { + "type": "string", + "example": "api" + } + }, + "type": "object" + }, + "RoleList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoleBrief" + } + }, + "RoleCreateRequest": { + "required": [ + "name" + ], + "properties": { + "name": { + "description": "역할명(테넌트+가드 내 고유)", + "type": "string", + "example": "menu-manager" + }, + "description": { + "type": "string", + "example": "메뉴 관리 역할", + "nullable": true + } + }, + "type": "object" + }, + "RoleUpdateRequest": { + "properties": { + "name": { + "type": "string", + "example": "menu-admin" + }, + "description": { + "type": "string", + "example": "설명 변경", + "nullable": true + } + }, + "type": "object" + }, + "PermissionBrief": { + "description": "퍼미션 요약", + "required": [ + "id", + "name", + "guard_name" + ], + "properties": { + "id": { + "type": "integer", + "example": 15 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "menu:101.view" + }, + "guard_name": { + "type": "string", + "example": "api" + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-16 10:00:00" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-08-16 10:00:00" + } + }, + "type": "object" + }, + "PermissionList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PermissionBrief" + } + }, + "RolePermissionGrantRequest": { + "description": "역할에 퍼미션 부여. 방법 A: permission_names 배열. 방법 B: menus + actions 조합.", + "type": "object", + "oneOf": [ + { + "description": "방법 A: 퍼미션 이름 배열", + "required": [ + "permission_names" + ], + "properties": { + "permission_names": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "menu:101.view", + "menu:101.create" + ] + } + }, + "type": "object" + }, + { + "description": "방법 B: 메뉴+액션 조합", + "required": [ + "menus", + "actions" + ], + "properties": { + "menus": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 101, + 102 + ] + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "view", + "create", + "update", + "delete" + ] + } + }, + "type": "object" + } + ] + }, + "RolePermissionRevokeRequest": { + "description": "역할에서 퍼미션 회수. 방법 A: permission_names 배열. 방법 B: menus + actions 조합.", + "type": "object", + "oneOf": [ + { + "description": "방법 A: 퍼미션 이름 배열", + "required": [ + "permission_names" + ], + "properties": { + "permission_names": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "menu:101.view", + "menu:101.create" + ] + } + }, + "type": "object" + }, + { + "description": "방법 B: 메뉴+액션 조합", + "required": [ + "menus", + "actions" + ], + "properties": { + "menus": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 101 + ] + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "create" + ] + } + }, + "type": "object" + } + ] + }, + "RolePermissionSyncRequest": { + "description": "역할의 퍼미션을 전달된 목록으로 완전히 교체(동기화). 방법 A 또는 B.", + "type": "object", + "oneOf": [ + { + "description": "방법 A: 퍼미션 이름 배열", + "required": [ + "permission_names" + ], + "properties": { + "permission_names": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "menu:101.view", + "menu:101.update" + ] + } + }, + "type": "object" + }, + { + "description": "방법 B: 메뉴+액션 조합", + "required": [ + "menus", + "actions" + ], + "properties": { + "menus": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 101, + 102 + ] + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "view", + "update" + ] + } + }, + "type": "object" + } + ] + }, + "Sale": { + "description": "매출 정보", + "properties": { + "id": { + "description": "매출 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "sale_number": { + "description": "매출번호", + "type": "string", + "example": "SL202501150001" + }, + "sale_date": { + "description": "매출일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "example": 100000 + }, + "total_amount": { + "description": "합계", + "type": "number", + "format": "float", + "example": 1100000 + }, + "description": { + "description": "적요", + "type": "string", + "example": "1월 매출", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "draft", + "confirmed", + "invoiced" + ], + "example": "draft" + }, + "tax_invoice_id": { + "description": "세금계산서 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "deposit_id": { + "description": "입금 연결 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client": { + "description": "거래처 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "(주)테스트" + } + }, + "type": "object", + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "SaleCreateRequest": { + "description": "매출 등록 요청", + "required": [ + "sale_date", + "client_id", + "supply_amount", + "tax_amount", + "total_amount" + ], + "properties": { + "sale_date": { + "description": "매출일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "example": 100000 + }, + "total_amount": { + "description": "합계", + "type": "number", + "format": "float", + "example": 1100000 + }, + "description": { + "description": "적요", + "type": "string", + "maxLength": 1000, + "example": "1월 매출", + "nullable": true + }, + "deposit_id": { + "description": "입금 연결 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "SaleUpdateRequest": { + "description": "매출 수정 요청", + "properties": { + "sale_date": { + "description": "매출일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "example": 100000 + }, + "total_amount": { + "description": "합계", + "type": "number", + "format": "float", + "example": 1100000 + }, + "description": { + "description": "적요", + "type": "string", + "maxLength": 1000, + "example": "1월 매출", + "nullable": true + }, + "deposit_id": { + "description": "입금 연결 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "SaleSummary": { + "description": "매출 요약", + "properties": { + "total_supply_amount": { + "description": "총 공급가액", + "type": "number", + "format": "float", + "example": 10000000 + }, + "total_tax_amount": { + "description": "총 세액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "total_amount": { + "description": "총 합계", + "type": "number", + "format": "float", + "example": 11000000 + }, + "total_count": { + "description": "총 건수", + "type": "integer", + "example": 10 + }, + "by_status": { + "description": "상태별 합계", + "properties": { + "draft": { + "properties": { + "total": { + "type": "number", + "example": 5500000 + }, + "count": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "confirmed": { + "properties": { + "total": { + "type": "number", + "example": 5500000 + }, + "count": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SaleStatementItem": { + "description": "거래명세서 품목", + "properties": { + "description": { + "description": "품목 설명", + "type": "string", + "example": "1월 매출" + }, + "quantity": { + "description": "수량", + "type": "integer", + "example": 1 + }, + "unit_price": { + "description": "단가", + "type": "number", + "example": 1000000 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "example": 100000 + }, + "total_amount": { + "description": "합계", + "type": "number", + "example": 1100000 + } + }, + "type": "object" + }, + "SaleStatementParty": { + "description": "거래명세서 거래 당사자 정보", + "properties": { + "name": { + "description": "상호", + "type": "string", + "example": "(주)테스트" + }, + "business_number": { + "description": "사업자번호", + "type": "string", + "example": "123-45-67890" + }, + "representative": { + "description": "대표자", + "type": "string", + "example": "홍길동" + }, + "address": { + "description": "주소", + "type": "string", + "example": "서울시 강남구" + }, + "tel": { + "description": "전화번호", + "type": "string", + "example": "02-1234-5678" + }, + "fax": { + "description": "팩스", + "type": "string", + "example": "02-1234-5679" + }, + "email": { + "description": "이메일", + "type": "string", + "example": "test@example.com" + } + }, + "type": "object" + }, + "SaleStatement": { + "description": "거래명세서 정보", + "properties": { + "statement_number": { + "description": "거래명세서 번호", + "type": "string", + "example": "STSL202501150001" + }, + "issued_at": { + "description": "발행일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "sale": { + "$ref": "#/components/schemas/Sale" + }, + "seller": { + "$ref": "#/components/schemas/SaleStatementParty" + }, + "buyer": { + "$ref": "#/components/schemas/SaleStatementParty" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SaleStatementItem" + } + }, + "summary": { + "properties": { + "supply_amount": { + "type": "number", + "example": 1000000 + }, + "tax_amount": { + "type": "number", + "example": 100000 + }, + "total_amount": { + "type": "number", + "example": 1100000 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SaleStatementIssueResponse": { + "description": "거래명세서 발행 응답", + "properties": { + "statement_number": { + "description": "거래명세서 번호", + "type": "string", + "example": "STSL202501150001" + }, + "issued_at": { + "description": "발행일시", + "type": "string", + "format": "date-time", + "example": "2025-01-15T10:30:00+09:00" + } + }, + "type": "object" + }, + "SaleStatementSendRequest": { + "description": "거래명세서 이메일 발송 요청", + "properties": { + "email": { + "description": "수신자 이메일 (미입력 시 거래처 이메일 사용)", + "type": "string", + "format": "email", + "example": "buyer@example.com", + "nullable": true + }, + "message": { + "description": "추가 메시지", + "type": "string", + "maxLength": 1000, + "example": "거래명세서를 발송합니다.", + "nullable": true + } + }, + "type": "object" + }, + "SaleStatementSendResponse": { + "description": "거래명세서 발송 응답", + "properties": { + "sent_to": { + "description": "발송 이메일", + "type": "string", + "format": "email", + "example": "buyer@example.com" + }, + "sent_at": { + "description": "발송일시", + "type": "string", + "format": "date-time", + "example": "2025-01-15T10:30:00+09:00" + }, + "statement_number": { + "description": "거래명세서 번호", + "type": "string", + "example": "STSL202501150001" + } + }, + "type": "object" + }, + "SaleBulkIssueStatementRequest": { + "description": "거래명세서 일괄 발행 요청", + "required": [ + "ids" + ], + "properties": { + "ids": { + "description": "발행할 매출 ID 목록 (최대 100개)", + "type": "array", + "items": { + "type": "integer", + "example": 1 + }, + "maxItems": 100, + "minItems": 1 + } + }, + "type": "object" + }, + "SaleBulkIssueStatementResponse": { + "description": "거래명세서 일괄 발행 응답", + "properties": { + "issued": { + "description": "발행 성공 건수", + "type": "integer", + "example": 8 + }, + "failed": { + "description": "발행 실패 건수", + "type": "integer", + "example": 2 + }, + "errors": { + "description": "실패 상세 (ID: 에러메시지)", + "type": "object", + "additionalProperties": { + "type": "string", + "example": "확정 상태가 아닌 매출입니다." + } + } + }, + "type": "object" + }, + "Shipment": { + "description": "출하 정보", + "properties": { + "id": { + "description": "출하 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "shipment_no": { + "description": "출하번호", + "type": "string", + "example": "SHP-20251226-0001" + }, + "lot_no": { + "description": "LOT번호", + "type": "string", + "example": "LOT-001", + "nullable": true + }, + "order_id": { + "description": "수주 ID", + "type": "integer", + "nullable": true + }, + "scheduled_date": { + "description": "출고예정일", + "type": "string", + "format": "date", + "example": "2025-12-26" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "scheduled", + "ready", + "shipping", + "completed" + ], + "example": "scheduled" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "출고예정" + }, + "priority": { + "description": "우선순위", + "type": "string", + "enum": [ + "urgent", + "normal", + "low" + ], + "example": "normal" + }, + "priority_label": { + "description": "우선순위 라벨", + "type": "string", + "example": "보통" + }, + "delivery_method": { + "description": "배송방식", + "type": "string", + "enum": [ + "pickup", + "direct", + "logistics" + ], + "example": "pickup" + }, + "delivery_method_label": { + "description": "배송방식 라벨", + "type": "string", + "example": "상차" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "nullable": true + }, + "customer_name": { + "description": "발주처명", + "type": "string", + "example": "(주)고객사", + "nullable": true + }, + "site_name": { + "description": "현장명", + "type": "string", + "example": "서울현장", + "nullable": true + }, + "delivery_address": { + "description": "배송주소", + "type": "string", + "example": "서울시 강남구", + "nullable": true + }, + "receiver": { + "description": "인수자", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "receiver_contact": { + "description": "인수자 연락처", + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "can_ship": { + "description": "출하가능 여부", + "type": "boolean", + "example": true + }, + "deposit_confirmed": { + "description": "입금확인 여부", + "type": "boolean", + "example": true + }, + "invoice_issued": { + "description": "세금계산서 발행 여부", + "type": "boolean", + "example": false + }, + "customer_grade": { + "description": "거래처 등급", + "type": "string", + "example": "A", + "nullable": true + }, + "loading_manager": { + "description": "상차담당자", + "type": "string", + "example": "김상차", + "nullable": true + }, + "loading_completed_at": { + "description": "상차완료 일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "loading_time": { + "description": "상차시간(입차예정)", + "type": "string", + "format": "date-time", + "nullable": true + }, + "logistics_company": { + "description": "물류사", + "type": "string", + "example": "CJ대한통운", + "nullable": true + }, + "vehicle_tonnage": { + "description": "차량 톤수", + "type": "string", + "example": "5톤", + "nullable": true + }, + "shipping_cost": { + "description": "운송비", + "type": "number", + "example": 150000, + "nullable": true + }, + "vehicle_no": { + "description": "차량번호", + "type": "string", + "example": "12가1234", + "nullable": true + }, + "driver_name": { + "description": "운전자명", + "type": "string", + "example": "이운전", + "nullable": true + }, + "driver_contact": { + "description": "운전자 연락처", + "type": "string", + "example": "010-9876-5432", + "nullable": true + }, + "expected_arrival": { + "description": "입차예정시간", + "type": "string", + "format": "date-time", + "nullable": true + }, + "confirmed_arrival": { + "description": "입차확정시간", + "type": "string", + "format": "date-time", + "nullable": true + }, + "remarks": { + "description": "비고", + "type": "string", + "nullable": true + }, + "is_urgent": { + "description": "긴급 여부", + "type": "boolean", + "example": false + }, + "item_count": { + "description": "품목 수", + "type": "integer", + "example": 3 + }, + "total_quantity": { + "description": "총 수량", + "type": "number", + "format": "float", + "example": 150.5 + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "ShipmentItem": { + "description": "출하 품목 정보", + "properties": { + "id": { + "description": "품목 ID", + "type": "integer", + "example": 1 + }, + "shipment_id": { + "description": "출하 ID", + "type": "integer", + "example": 1 + }, + "seq": { + "description": "순번", + "type": "integer", + "example": 1 + }, + "item_code": { + "description": "품목코드", + "type": "string", + "example": "ITEM-001", + "nullable": true + }, + "item_name": { + "description": "품목명", + "type": "string", + "example": "제품 A" + }, + "floor_unit": { + "description": "층/M호", + "type": "string", + "example": "1층/M01", + "nullable": true + }, + "specification": { + "description": "규격", + "type": "string", + "example": "100x200mm", + "nullable": true + }, + "quantity": { + "description": "수량", + "type": "number", + "format": "float", + "example": 10.5 + }, + "unit": { + "description": "단위", + "type": "string", + "example": "EA", + "nullable": true + }, + "lot_no": { + "description": "LOT번호", + "type": "string", + "example": "LOT-001", + "nullable": true + }, + "stock_lot_id": { + "description": "재고 LOT ID", + "type": "integer", + "nullable": true + }, + "remarks": { + "description": "비고", + "type": "string", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "ShipmentWithItems": { + "description": "출하 상세 정보 (품목 포함)", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Shipment" + }, + { + "properties": { + "items": { + "description": "출하 품목 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/ShipmentItem" + } + } + }, + "type": "object" + } + ] + }, + "ShipmentStats": { + "description": "출하 통계", + "properties": { + "total": { + "description": "전체 건수", + "type": "integer", + "example": 100 + }, + "scheduled": { + "description": "출고예정 건수", + "type": "integer", + "example": 30 + }, + "ready": { + "description": "출하대기 건수", + "type": "integer", + "example": 20 + }, + "shipping": { + "description": "배송중 건수", + "type": "integer", + "example": 15 + }, + "completed": { + "description": "배송완료 건수", + "type": "integer", + "example": 35 + }, + "urgent": { + "description": "긴급 건수", + "type": "integer", + "example": 5 + }, + "today_scheduled": { + "description": "오늘 출고예정 건수", + "type": "integer", + "example": 10 + } + }, + "type": "object" + }, + "ShipmentStatsByStatus": { + "description": "상태별 출하 통계", + "properties": { + "scheduled": { + "properties": { + "label": { + "type": "string", + "example": "출고예정" + }, + "count": { + "type": "integer", + "example": 30 + } + }, + "type": "object" + }, + "ready": { + "properties": { + "label": { + "type": "string", + "example": "출하대기" + }, + "count": { + "type": "integer", + "example": 20 + } + }, + "type": "object" + }, + "shipping": { + "properties": { + "label": { + "type": "string", + "example": "배송중" + }, + "count": { + "type": "integer", + "example": 15 + } + }, + "type": "object" + }, + "completed": { + "properties": { + "label": { + "type": "string", + "example": "배송완료" + }, + "count": { + "type": "integer", + "example": 35 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ShipmentStoreRequest": { + "required": [ + "scheduled_date" + ], + "properties": { + "shipment_no": { + "description": "출하번호 (자동 생성 가능)", + "type": "string", + "example": "SHP-20251226-0001" + }, + "lot_no": { + "description": "LOT번호", + "type": "string", + "example": "LOT-001" + }, + "order_id": { + "description": "수주 ID", + "type": "integer", + "example": 1 + }, + "scheduled_date": { + "description": "출고예정일", + "type": "string", + "format": "date", + "example": "2025-12-26" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "scheduled", + "ready", + "shipping", + "completed" + ], + "example": "scheduled" + }, + "priority": { + "description": "우선순위", + "type": "string", + "enum": [ + "urgent", + "normal", + "low" + ], + "example": "normal" + }, + "delivery_method": { + "description": "배송방식", + "type": "string", + "enum": [ + "pickup", + "direct", + "logistics" + ], + "example": "pickup" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer" + }, + "customer_name": { + "description": "발주처명", + "type": "string", + "example": "(주)고객사" + }, + "site_name": { + "description": "현장명", + "type": "string", + "example": "서울현장" + }, + "delivery_address": { + "description": "배송주소", + "type": "string", + "example": "서울시 강남구" + }, + "receiver": { + "description": "인수자", + "type": "string", + "example": "홍길동" + }, + "receiver_contact": { + "description": "인수자 연락처", + "type": "string", + "example": "010-1234-5678" + }, + "can_ship": { + "description": "출하가능 여부", + "type": "boolean", + "example": true + }, + "deposit_confirmed": { + "description": "입금확인 여부", + "type": "boolean", + "example": true + }, + "invoice_issued": { + "description": "세금계산서 발행 여부", + "type": "boolean", + "example": false + }, + "loading_manager": { + "description": "상차담당자", + "type": "string" + }, + "loading_time": { + "description": "상차시간", + "type": "string", + "format": "date-time" + }, + "logistics_company": { + "description": "물류사", + "type": "string" + }, + "vehicle_tonnage": { + "description": "차량 톤수", + "type": "string" + }, + "shipping_cost": { + "description": "운송비", + "type": "number" + }, + "vehicle_no": { + "description": "차량번호", + "type": "string" + }, + "driver_name": { + "description": "운전자명", + "type": "string" + }, + "driver_contact": { + "description": "운전자 연락처", + "type": "string" + }, + "expected_arrival": { + "description": "입차예정시간", + "type": "string", + "format": "date-time" + }, + "remarks": { + "description": "비고", + "type": "string" + }, + "items": { + "description": "출하 품목", + "type": "array", + "items": { + "properties": { + "seq": { + "type": "integer", + "example": 1 + }, + "item_code": { + "type": "string", + "example": "ITEM-001" + }, + "item_name": { + "type": "string", + "example": "제품 A" + }, + "floor_unit": { + "type": "string", + "example": "1층/M01" + }, + "specification": { + "type": "string", + "example": "100x200mm" + }, + "quantity": { + "type": "number", + "example": 10.5 + }, + "unit": { + "type": "string", + "example": "EA" + }, + "lot_no": { + "type": "string", + "example": "LOT-001" + }, + "stock_lot_id": { + "type": "integer" + }, + "remarks": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "ShipmentUpdateStatusRequest": { + "required": [ + "status" + ], + "properties": { + "status": { + "description": "변경할 상태", + "type": "string", + "enum": [ + "scheduled", + "ready", + "shipping", + "completed" + ], + "example": "shipping" + }, + "loading_time": { + "description": "상차시간 (ready 상태 시)", + "type": "string", + "format": "date-time" + }, + "loading_completed_at": { + "description": "상차완료 일시 (shipping 상태 시)", + "type": "string", + "format": "date-time" + }, + "vehicle_no": { + "description": "차량번호 (shipping 상태 시)", + "type": "string" + }, + "driver_name": { + "description": "운전자명 (shipping 상태 시)", + "type": "string" + }, + "driver_contact": { + "description": "운전자 연락처 (shipping 상태 시)", + "type": "string" + }, + "confirmed_arrival": { + "description": "입차확정시간 (completed 상태 시)", + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "LotOption": { + "description": "LOT 옵션", + "properties": { + "id": { + "description": "LOT ID", + "type": "integer", + "example": 1 + }, + "lot_no": { + "description": "LOT번호", + "type": "string", + "example": "251226-01" + }, + "item_code": { + "description": "품목코드", + "type": "string", + "example": "ITEM-001" + }, + "item_name": { + "description": "품목명", + "type": "string", + "example": "원재료 A" + }, + "qty": { + "description": "수량", + "type": "number", + "format": "float", + "example": 100 + }, + "available_qty": { + "description": "가용수량", + "type": "number", + "format": "float", + "example": 80 + }, + "unit": { + "description": "단위", + "type": "string", + "example": "EA" + }, + "location": { + "description": "위치", + "type": "string", + "example": "A-01-01" + }, + "fifo_order": { + "description": "FIFO 순서", + "type": "integer", + "example": 1 + } + }, + "type": "object" + }, + "Site": { + "description": "현장 정보", + "properties": { + "id": { + "description": "현장 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "현장명", + "type": "string", + "example": "강남 현장" + }, + "address": { + "description": "현장 주소", + "type": "string", + "example": "서울시 강남구 테헤란로 123", + "nullable": true + }, + "latitude": { + "description": "위도", + "type": "number", + "format": "float", + "example": 37.5012, + "nullable": true + }, + "longitude": { + "description": "경도", + "type": "number", + "format": "float", + "example": 127.0396, + "nullable": true + }, + "is_active": { + "description": "활성화 여부", + "type": "boolean", + "example": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "description": "수정자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "SiteCreateRequest": { + "description": "현장 등록 요청", + "required": [ + "name" + ], + "properties": { + "name": { + "description": "현장명", + "type": "string", + "maxLength": 100, + "example": "강남 현장" + }, + "address": { + "description": "현장 주소", + "type": "string", + "maxLength": 255, + "example": "서울시 강남구 테헤란로 123" + }, + "latitude": { + "description": "위도", + "type": "number", + "format": "float", + "maximum": 90, + "minimum": -90, + "example": 37.5012 + }, + "longitude": { + "description": "경도", + "type": "number", + "format": "float", + "maximum": 180, + "minimum": -180, + "example": 127.0396 + }, + "is_active": { + "description": "활성화 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "SiteUpdateRequest": { + "description": "현장 수정 요청", + "properties": { + "name": { + "description": "현장명", + "type": "string", + "maxLength": 100, + "example": "강남 현장" + }, + "address": { + "description": "현장 주소", + "type": "string", + "maxLength": 255, + "example": "서울시 강남구 테헤란로 123" + }, + "latitude": { + "description": "위도", + "type": "number", + "format": "float", + "maximum": 90, + "minimum": -90, + "example": 37.5012 + }, + "longitude": { + "description": "경도", + "type": "number", + "format": "float", + "maximum": 180, + "minimum": -180, + "example": 127.0396 + }, + "is_active": { + "description": "활성화 여부", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "SiteListItem": { + "description": "현장 목록 아이템 (셀렉트박스용)", + "properties": { + "id": { + "description": "현장 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "현장명", + "type": "string", + "example": "강남 현장" + }, + "address": { + "description": "현장 주소", + "type": "string", + "example": "서울시 강남구", + "nullable": true + } + }, + "type": "object" + }, + "StatSalesDaily": { + "description": "일간 매출 통계", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 287 + }, + "stat_date": { + "type": "string", + "format": "date", + "example": "2026-01-28" + }, + "order_count": { + "description": "수주 건수", + "type": "integer", + "example": 5 + }, + "order_amount": { + "description": "수주 금액", + "type": "number", + "format": "float", + "example": 15000000 + }, + "sales_count": { + "description": "매출 건수", + "type": "integer", + "example": 3 + }, + "sales_amount": { + "description": "매출 금액", + "type": "number", + "format": "float", + "example": 12000000 + }, + "sales_tax_amount": { + "description": "매출 세액", + "type": "number", + "format": "float", + "example": 1200000 + }, + "new_client_count": { + "description": "신규 고객 수", + "type": "integer", + "example": 1 + }, + "active_client_count": { + "description": "활성 고객 수", + "type": "integer", + "example": 4 + }, + "shipment_count": { + "description": "출하 건수", + "type": "integer", + "example": 2 + }, + "shipment_amount": { + "description": "출하 금액", + "type": "number", + "format": "float", + "example": 500000 + } + }, + "type": "object" + }, + "StatFinanceDaily": { + "description": "일간 재무 통계", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 287 + }, + "stat_date": { + "type": "string", + "format": "date", + "example": "2026-01-28" + }, + "deposit_count": { + "description": "입금 건수", + "type": "integer", + "example": 3 + }, + "deposit_amount": { + "description": "입금 금액", + "type": "number", + "format": "float", + "example": 5000000 + }, + "withdrawal_count": { + "description": "출금 건수", + "type": "integer", + "example": 5 + }, + "withdrawal_amount": { + "description": "출금 금액", + "type": "number", + "format": "float", + "example": 3000000 + }, + "net_cashflow": { + "description": "순 현금 흐름", + "type": "number", + "format": "float", + "example": 2000000 + }, + "purchase_count": { + "description": "매입 건수", + "type": "integer", + "example": 2 + }, + "purchase_amount": { + "description": "매입 금액", + "type": "number", + "format": "float", + "example": 8000000 + }, + "bank_balance_total": { + "description": "은행 잔액 합계", + "type": "number", + "format": "float", + "example": 150000000 + } + }, + "type": "object" + }, + "StatDashboardSummary": { + "description": "대시보드 통계 요약 (sam_stat 기반)", + "properties": { + "sales_today": { + "oneOf": [ + { + "$ref": "#/components/schemas/StatSalesDaily" + } + ], + "nullable": true, + "description": "오늘 매출 통계" + }, + "finance_today": { + "oneOf": [ + { + "$ref": "#/components/schemas/StatFinanceDaily" + } + ], + "nullable": true, + "description": "오늘 재무 통계" + }, + "production_today": { + "description": "오늘 생산 통계", + "type": "object", + "nullable": true + }, + "sales_monthly": { + "description": "이번 달 매출 요약", + "type": "object", + "nullable": true + }, + "alerts": { + "description": "미읽은/미해결 알림 (최대 10건)", + "type": "array", + "items": { + "$ref": "#/components/schemas/StatAlert" + } + } + }, + "type": "object" + }, + "StatAlert": { + "description": "통계 알림", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 287 + }, + "domain": { + "description": "도메인", + "type": "string", + "example": "sales" + }, + "alert_type": { + "description": "알림 유형", + "type": "string", + "example": "aggregation_failure" + }, + "severity": { + "description": "심각도", + "type": "string", + "enum": [ + "info", + "warning", + "critical" + ], + "example": "critical" + }, + "title": { + "description": "제목", + "type": "string", + "example": "[sales_daily] 집계 실패" + }, + "message": { + "description": "상세 메시지", + "type": "string", + "example": "오류 상세 메시지" + }, + "current_value": { + "description": "현재 값", + "type": "number", + "format": "float", + "example": 0, + "nullable": true + }, + "threshold_value": { + "description": "기준 값", + "type": "number", + "format": "float", + "example": 1, + "nullable": true + }, + "is_read": { + "description": "읽음 여부", + "type": "boolean", + "example": false + }, + "is_resolved": { + "description": "해결 여부", + "type": "boolean", + "example": false + }, + "resolved_at": { + "description": "해결 일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "created_at": { + "description": "생성 일시", + "type": "string", + "format": "date-time", + "example": "2026-01-28T10:00:00Z" + } + }, + "type": "object" + }, + "StatusBoardItem": { + "description": "현황판 카드 아이템", + "properties": { + "id": { + "description": "카드 ID", + "type": "string", + "example": "orders" + }, + "label": { + "description": "카드 라벨", + "type": "string", + "example": "수주" + }, + "count": { + "description": "건수 또는 텍스트", + "oneOf": [ + { + "type": "integer", + "example": 3 + }, + { + "type": "string", + "example": "부가세 신고 D-15" + } + ] + }, + "path": { + "description": "이동 경로", + "type": "string", + "example": "/sales/order-management-sales" + }, + "isHighlighted": { + "description": "강조 표시 여부", + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "StatusBoardSummary": { + "description": "현황판 요약 데이터", + "properties": { + "items": { + "description": "현황판 카드 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/StatusBoardItem" + } + } + }, + "type": "object" + }, + "Stock": { + "description": "재고 정보", + "properties": { + "id": { + "description": "재고 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "item_code": { + "description": "품목코드", + "type": "string", + "example": "ITEM-001" + }, + "item_name": { + "description": "품목명", + "type": "string", + "example": "원재료 A" + }, + "item_type": { + "description": "품목유형", + "type": "string", + "enum": [ + "raw_material", + "bent_part", + "purchased_part", + "sub_material", + "consumable" + ], + "example": "raw_material" + }, + "item_type_label": { + "description": "품목유형 라벨", + "type": "string", + "example": "원자재" + }, + "specification": { + "description": "규격", + "type": "string", + "example": "100x100mm", + "nullable": true + }, + "unit": { + "description": "단위", + "type": "string", + "example": "EA" + }, + "stock_qty": { + "description": "현재 재고량", + "type": "number", + "format": "float", + "example": 150.5 + }, + "safety_stock": { + "description": "안전 재고", + "type": "number", + "format": "float", + "example": 50 + }, + "reserved_qty": { + "description": "예약 수량", + "type": "number", + "format": "float", + "example": 20 + }, + "available_qty": { + "description": "가용 수량", + "type": "number", + "format": "float", + "example": 130.5 + }, + "lot_count": { + "description": "LOT 개수", + "type": "integer", + "example": 3 + }, + "oldest_lot_date": { + "description": "가장 오래된 LOT 입고일", + "type": "string", + "format": "date", + "example": "2025-11-15", + "nullable": true + }, + "days_elapsed": { + "description": "경과일 (가장 오래된 LOT 기준)", + "type": "integer", + "example": 41 + }, + "location": { + "description": "위치", + "type": "string", + "example": "A-01-01", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "normal", + "low", + "out" + ], + "example": "normal" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "정상" + }, + "last_receipt_date": { + "description": "마지막 입고일", + "type": "string", + "format": "date", + "example": "2025-12-20", + "nullable": true + }, + "last_issue_date": { + "description": "마지막 출고일", + "type": "string", + "format": "date", + "example": "2025-12-24", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "StockLot": { + "description": "재고 LOT 정보", + "properties": { + "id": { + "description": "LOT ID", + "type": "integer", + "example": 1 + }, + "stock_id": { + "description": "재고 ID", + "type": "integer", + "example": 1 + }, + "lot_no": { + "description": "LOT번호", + "type": "string", + "example": "251226-01" + }, + "fifo_order": { + "description": "FIFO 순서", + "type": "integer", + "example": 1 + }, + "receipt_date": { + "description": "입고일", + "type": "string", + "format": "date", + "example": "2025-12-26" + }, + "qty": { + "description": "수량", + "type": "number", + "format": "float", + "example": 50 + }, + "reserved_qty": { + "description": "예약 수량", + "type": "number", + "format": "float", + "example": 10 + }, + "available_qty": { + "description": "가용 수량", + "type": "number", + "format": "float", + "example": 40 + }, + "unit": { + "description": "단위", + "type": "string", + "example": "EA", + "nullable": true + }, + "supplier": { + "description": "공급업체", + "type": "string", + "example": "(주)공급사", + "nullable": true + }, + "supplier_lot": { + "description": "공급업체 LOT", + "type": "string", + "example": "SUP-LOT-001", + "nullable": true + }, + "po_number": { + "description": "발주번호", + "type": "string", + "example": "PO-2025-001", + "nullable": true + }, + "location": { + "description": "위치", + "type": "string", + "example": "A-01-01", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "available", + "reserved", + "used" + ], + "example": "available" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "사용가능" + }, + "days_elapsed": { + "description": "경과일", + "type": "integer", + "example": 1 + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "StockWithLots": { + "description": "재고 상세 정보 (LOT 포함)", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Stock" + }, + { + "properties": { + "lots": { + "description": "LOT 목록 (FIFO 순서)", + "type": "array", + "items": { + "$ref": "#/components/schemas/StockLot" + } + } + }, + "type": "object" + } + ] + }, + "StockStats": { + "description": "재고 통계", + "properties": { + "total_items": { + "description": "전체 품목 수", + "type": "integer", + "example": 150 + }, + "normal_count": { + "description": "정상 재고 품목 수", + "type": "integer", + "example": 120 + }, + "low_count": { + "description": "부족 재고 품목 수", + "type": "integer", + "example": 20 + }, + "out_count": { + "description": "재고 없음 품목 수", + "type": "integer", + "example": 10 + } + }, + "type": "object" + }, + "StockStatsByItemType": { + "description": "품목유형별 재고 통계", + "properties": { + "raw_material": { + "properties": { + "label": { + "type": "string", + "example": "원자재" + }, + "count": { + "type": "integer", + "example": 50 + }, + "total_qty": { + "type": "number", + "format": "float", + "example": 5000 + } + }, + "type": "object" + }, + "bent_part": { + "properties": { + "label": { + "type": "string", + "example": "절곡부품" + }, + "count": { + "type": "integer", + "example": 30 + }, + "total_qty": { + "type": "number", + "format": "float", + "example": 2500 + } + }, + "type": "object" + }, + "purchased_part": { + "properties": { + "label": { + "type": "string", + "example": "구매부품" + }, + "count": { + "type": "integer", + "example": 40 + }, + "total_qty": { + "type": "number", + "format": "float", + "example": 3000 + } + }, + "type": "object" + }, + "sub_material": { + "properties": { + "label": { + "type": "string", + "example": "부자재" + }, + "count": { + "type": "integer", + "example": 20 + }, + "total_qty": { + "type": "number", + "format": "float", + "example": 1500 + } + }, + "type": "object" + }, + "consumable": { + "properties": { + "label": { + "type": "string", + "example": "소모품" + }, + "count": { + "type": "integer", + "example": 10 + }, + "total_qty": { + "type": "number", + "format": "float", + "example": 500 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Subscription": { + "description": "구독 정보", + "properties": { + "id": { + "description": "구독 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "plan_id": { + "description": "요금제 ID", + "type": "integer", + "example": 1 + }, + "started_at": { + "description": "시작일", + "type": "string", + "format": "date-time", + "example": "2025-01-01T00:00:00" + }, + "ended_at": { + "description": "종료일", + "type": "string", + "format": "date-time", + "example": "2025-02-01T00:00:00", + "nullable": true + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "pending", + "active", + "cancelled", + "expired", + "suspended" + ], + "example": "active" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "활성" + }, + "cancelled_at": { + "description": "취소일", + "type": "string", + "format": "date-time", + "nullable": true + }, + "cancel_reason": { + "description": "취소 사유", + "type": "string", + "nullable": true + }, + "is_expired": { + "description": "만료 여부", + "type": "boolean", + "example": false + }, + "is_valid": { + "description": "유효 여부", + "type": "boolean", + "example": true + }, + "remaining_days": { + "description": "남은 일수 (무제한은 null)", + "type": "integer", + "example": 30, + "nullable": true + }, + "total_paid": { + "description": "총 결제 금액", + "type": "number", + "format": "float", + "example": 29000 + }, + "plan": { + "description": "요금제 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "스타터" + }, + "code": { + "type": "string", + "example": "starter" + }, + "price": { + "type": "number", + "format": "float", + "example": 29000 + }, + "billing_cycle": { + "type": "string", + "example": "monthly" + } + }, + "type": "object", + "nullable": true + }, + "payments": { + "description": "결제 내역", + "type": "array", + "items": { + "$ref": "#/components/schemas/Payment" + }, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "SubscriptionCreateRequest": { + "description": "구독 등록 요청", + "required": [ + "plan_id" + ], + "properties": { + "plan_id": { + "description": "요금제 ID", + "type": "integer", + "example": 1 + }, + "started_at": { + "description": "시작일 (미지정 시 현재)", + "type": "string", + "format": "date", + "example": "2025-01-01", + "nullable": true + }, + "payment_method": { + "description": "결제 수단", + "type": "string", + "enum": [ + "card", + "bank", + "virtual", + "cash", + "free" + ], + "example": "card" + }, + "transaction_id": { + "description": "PG 거래 ID", + "type": "string", + "example": "TXN123456", + "nullable": true + }, + "auto_complete": { + "description": "자동 결제 완료 처리", + "type": "boolean", + "example": true + } + }, + "type": "object" + }, + "SubscriptionCancelRequest": { + "description": "구독 취소 요청", + "properties": { + "reason": { + "description": "취소 사유", + "type": "string", + "maxLength": 500, + "example": "서비스 불만족", + "nullable": true + } + }, + "type": "object" + }, + "UsageResponse": { + "description": "사용량 정보", + "properties": { + "users": { + "properties": { + "used": { + "description": "현재 사용자 수", + "type": "integer", + "example": 5 + }, + "limit": { + "description": "최대 사용자 수", + "type": "integer", + "example": 10 + }, + "percentage": { + "description": "사용률 (%)", + "type": "number", + "format": "float", + "example": 50 + } + }, + "type": "object" + }, + "storage": { + "properties": { + "used": { + "description": "사용 용량 (bytes)", + "type": "integer", + "example": 1288490188 + }, + "used_formatted": { + "description": "사용 용량 (포맷)", + "type": "string", + "example": "1.2 GB" + }, + "limit": { + "description": "최대 용량 (bytes)", + "type": "integer", + "example": 10737418240 + }, + "limit_formatted": { + "description": "최대 용량 (포맷)", + "type": "string", + "example": "10 GB" + }, + "percentage": { + "description": "사용률 (%)", + "type": "number", + "format": "float", + "example": 12 + } + }, + "type": "object" + }, + "subscription": { + "properties": { + "plan": { + "description": "요금제명", + "type": "string", + "example": "스타터", + "nullable": true + }, + "status": { + "description": "구독 상태", + "type": "string", + "example": "active", + "nullable": true + }, + "remaining_days": { + "description": "남은 일수", + "type": "integer", + "example": 25, + "nullable": true + }, + "started_at": { + "type": "string", + "format": "date", + "example": "2025-01-01", + "nullable": true + }, + "ended_at": { + "type": "string", + "format": "date", + "example": "2025-02-01", + "nullable": true + } + }, + "type": "object" + } + }, + "type": "object" + }, + "DataExport": { + "description": "데이터 내보내기 정보", + "properties": { + "id": { + "description": "ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "export_type": { + "description": "내보내기 유형", + "type": "string", + "enum": [ + "all", + "users", + "products", + "orders", + "clients" + ], + "example": "all" + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "pending", + "processing", + "completed", + "failed" + ], + "example": "pending" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "대기중" + }, + "file_path": { + "description": "파일 경로", + "type": "string", + "nullable": true + }, + "file_name": { + "description": "파일명", + "type": "string", + "nullable": true + }, + "file_size": { + "description": "파일 크기 (bytes)", + "type": "integer", + "nullable": true + }, + "file_size_formatted": { + "description": "파일 크기 (포맷)", + "type": "string", + "example": "1.5 MB" + }, + "options": { + "description": "내보내기 옵션", + "type": "object", + "nullable": true + }, + "started_at": { + "description": "시작 시간", + "type": "string", + "format": "date-time", + "nullable": true + }, + "completed_at": { + "description": "완료 시간", + "type": "string", + "format": "date-time", + "nullable": true + }, + "error_message": { + "description": "에러 메시지", + "type": "string", + "nullable": true + }, + "is_completed": { + "description": "완료 여부", + "type": "boolean", + "example": false + }, + "is_downloadable": { + "description": "다운로드 가능 여부", + "type": "boolean", + "example": false + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "ExportCreateRequest": { + "description": "내보내기 요청", + "required": [ + "export_type" + ], + "properties": { + "export_type": { + "description": "내보내기 유형", + "type": "string", + "enum": [ + "all", + "users", + "products", + "orders", + "clients" + ], + "example": "all" + }, + "options": { + "properties": { + "format": { + "description": "파일 포맷", + "type": "string", + "enum": [ + "xlsx", + "csv", + "json" + ], + "example": "xlsx" + }, + "include_deleted": { + "description": "삭제된 데이터 포함 여부", + "type": "boolean", + "example": false + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "TaxInvoice": { + "description": "세금계산서 정보", + "properties": { + "id": { + "description": "세금계산서 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "nts_confirm_num": { + "description": "국세청 승인번호", + "type": "string", + "example": "20250115-12345678-12345678", + "nullable": true + }, + "invoice_type": { + "description": "세금계산서 유형", + "type": "string", + "enum": [ + "tax_invoice", + "invoice", + "modified" + ], + "example": "tax_invoice" + }, + "issue_type": { + "description": "발행 유형", + "type": "string", + "enum": [ + "normal", + "reverse", + "trustee" + ], + "example": "normal" + }, + "direction": { + "description": "방향 (매출/매입)", + "type": "string", + "enum": [ + "sales", + "purchases" + ], + "example": "sales" + }, + "supplier_corp_num": { + "description": "공급자 사업자번호", + "type": "string", + "example": "1234567890" + }, + "supplier_corp_name": { + "description": "공급자 회사명", + "type": "string", + "example": "(주)공급사" + }, + "supplier_ceo_name": { + "description": "공급자 대표자명", + "type": "string", + "example": "홍길동" + }, + "supplier_addr": { + "description": "공급자 주소", + "type": "string", + "example": "서울시 강남구", + "nullable": true + }, + "supplier_biz_type": { + "description": "공급자 업태", + "type": "string", + "example": "서비스", + "nullable": true + }, + "supplier_biz_class": { + "description": "공급자 종목", + "type": "string", + "example": "소프트웨어", + "nullable": true + }, + "supplier_contact_id": { + "description": "공급자 담당자 이메일", + "type": "string", + "example": "supplier@test.com", + "nullable": true + }, + "buyer_corp_num": { + "description": "공급받는자 사업자번호", + "type": "string", + "example": "0987654321" + }, + "buyer_corp_name": { + "description": "공급받는자 회사명", + "type": "string", + "example": "(주)구매사" + }, + "buyer_ceo_name": { + "description": "공급받는자 대표자명", + "type": "string", + "example": "김대표" + }, + "buyer_addr": { + "description": "공급받는자 주소", + "type": "string", + "example": "서울시 서초구", + "nullable": true + }, + "buyer_biz_type": { + "description": "공급받는자 업태", + "type": "string", + "example": "제조", + "nullable": true + }, + "buyer_biz_class": { + "description": "공급받는자 종목", + "type": "string", + "example": "전자제품", + "nullable": true + }, + "buyer_contact_id": { + "description": "공급받는자 담당자 이메일", + "type": "string", + "example": "buyer@test.com", + "nullable": true + }, + "issue_date": { + "description": "작성일자", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "example": 100000 + }, + "total_amount": { + "description": "합계금액", + "type": "number", + "format": "float", + "example": 1100000 + }, + "items": { + "description": "품목 목록", + "type": "array", + "items": { + "properties": { + "date": { + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "name": { + "type": "string", + "example": "컨설팅 서비스" + }, + "spec": { + "type": "string", + "example": "월간" + }, + "quantity": { + "type": "number", + "example": 1 + }, + "unit_price": { + "type": "number", + "example": 1000000 + }, + "supply_amount": { + "type": "number", + "example": 1000000 + }, + "tax_amount": { + "type": "number", + "example": 100000 + }, + "remark": { + "type": "string", + "example": "1월분", + "nullable": true + } + }, + "type": "object" + } + }, + "status": { + "description": "상태", + "type": "string", + "enum": [ + "draft", + "issued", + "sent", + "cancelled", + "failed" + ], + "example": "draft" + }, + "status_label": { + "description": "상태 라벨", + "type": "string", + "example": "임시저장" + }, + "invoice_type_label": { + "description": "세금계산서 유형 라벨", + "type": "string", + "example": "세금계산서" + }, + "issue_type_label": { + "description": "발행 유형 라벨", + "type": "string", + "example": "정발행" + }, + "direction_label": { + "description": "방향 라벨", + "type": "string", + "example": "매출" + }, + "formatted_supplier_corp_num": { + "description": "포맷팅된 공급자 사업자번호", + "type": "string", + "example": "123-45-67890" + }, + "formatted_buyer_corp_num": { + "description": "포맷팅된 공급받는자 사업자번호", + "type": "string", + "example": "098-76-54321" + }, + "nts_send_status": { + "description": "국세청 전송 상태", + "type": "string", + "example": "success", + "nullable": true + }, + "issued_at": { + "description": "발행 일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "sent_at": { + "description": "국세청 전송 일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "cancelled_at": { + "description": "취소 일시", + "type": "string", + "format": "date-time", + "nullable": true + }, + "barobill_invoice_id": { + "description": "바로빌 발행 ID", + "type": "string", + "nullable": true + }, + "description": { + "description": "비고", + "type": "string", + "nullable": true + }, + "error_message": { + "description": "에러 메시지", + "type": "string", + "nullable": true + }, + "reference_type": { + "description": "참조 모델 타입", + "type": "string", + "example": "App\\\\Models\\\\Tenants\\\\Sale", + "nullable": true + }, + "reference_id": { + "description": "참조 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "creator": { + "description": "생성자 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "관리자" + } + }, + "type": "object", + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "description": "수정자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "deleted_by": { + "description": "삭제자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "TaxInvoiceCreateRequest": { + "description": "세금계산서 생성 요청", + "required": [ + "invoice_type", + "issue_type", + "direction", + "supplier_corp_num", + "supplier_corp_name", + "supplier_ceo_name", + "buyer_corp_num", + "buyer_corp_name", + "buyer_ceo_name", + "issue_date", + "supply_amount", + "tax_amount" + ], + "properties": { + "invoice_type": { + "description": "세금계산서 유형", + "type": "string", + "enum": [ + "tax_invoice", + "invoice", + "modified" + ], + "example": "tax_invoice" + }, + "issue_type": { + "description": "발행 유형", + "type": "string", + "enum": [ + "normal", + "reverse", + "trustee" + ], + "example": "normal" + }, + "direction": { + "description": "방향 (매출/매입)", + "type": "string", + "enum": [ + "sales", + "purchases" + ], + "example": "sales" + }, + "supplier_corp_num": { + "description": "공급자 사업자번호", + "type": "string", + "maxLength": 10, + "minLength": 10, + "example": "1234567890" + }, + "supplier_corp_name": { + "description": "공급자 회사명", + "type": "string", + "maxLength": 200, + "example": "(주)공급사" + }, + "supplier_ceo_name": { + "description": "공급자 대표자명", + "type": "string", + "maxLength": 100, + "example": "홍길동" + }, + "supplier_addr": { + "description": "공급자 주소", + "type": "string", + "maxLength": 500, + "example": "서울시 강남구", + "nullable": true + }, + "supplier_biz_type": { + "description": "공급자 업태", + "type": "string", + "maxLength": 100, + "example": "서비스", + "nullable": true + }, + "supplier_biz_class": { + "description": "공급자 종목", + "type": "string", + "maxLength": 100, + "example": "소프트웨어", + "nullable": true + }, + "supplier_contact_id": { + "description": "공급자 담당자 이메일", + "type": "string", + "maxLength": 100, + "example": "supplier@test.com", + "nullable": true + }, + "buyer_corp_num": { + "description": "공급받는자 사업자번호", + "type": "string", + "maxLength": 10, + "minLength": 10, + "example": "0987654321" + }, + "buyer_corp_name": { + "description": "공급받는자 회사명", + "type": "string", + "maxLength": 200, + "example": "(주)구매사" + }, + "buyer_ceo_name": { + "description": "공급받는자 대표자명", + "type": "string", + "maxLength": 100, + "example": "김대표" + }, + "buyer_addr": { + "description": "공급받는자 주소", + "type": "string", + "maxLength": 500, + "example": "서울시 서초구", + "nullable": true + }, + "buyer_biz_type": { + "description": "공급받는자 업태", + "type": "string", + "maxLength": 100, + "example": "제조", + "nullable": true + }, + "buyer_biz_class": { + "description": "공급받는자 종목", + "type": "string", + "maxLength": 100, + "example": "전자제품", + "nullable": true + }, + "buyer_contact_id": { + "description": "공급받는자 담당자 이메일", + "type": "string", + "maxLength": 100, + "example": "buyer@test.com", + "nullable": true + }, + "issue_date": { + "description": "작성일자", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "minimum": 0, + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "minimum": 0, + "example": 100000 + }, + "items": { + "description": "품목 목록 (최대 99개)", + "type": "array", + "items": { + "properties": { + "date": { + "description": "거래일자", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "name": { + "description": "품목명", + "type": "string", + "maxLength": 200, + "example": "컨설팅 서비스" + }, + "spec": { + "description": "규격", + "type": "string", + "maxLength": 100, + "example": "월간", + "nullable": true + }, + "quantity": { + "description": "수량", + "type": "number", + "minimum": 0, + "example": 1 + }, + "unit_price": { + "description": "단가", + "type": "number", + "minimum": 0, + "example": 1000000 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "minimum": 0, + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "minimum": 0, + "example": 100000 + }, + "remark": { + "description": "비고", + "type": "string", + "maxLength": 200, + "example": "1월분", + "nullable": true + } + }, + "type": "object" + } + }, + "description": { + "description": "비고", + "type": "string", + "maxLength": 500, + "example": "월간 컨설팅 비용", + "nullable": true + } + }, + "type": "object" + }, + "TaxInvoiceUpdateRequest": { + "description": "세금계산서 수정 요청 (임시저장 상태에서만 수정 가능)", + "properties": { + "invoice_type": { + "description": "세금계산서 유형", + "type": "string", + "enum": [ + "tax_invoice", + "invoice", + "modified" + ], + "example": "tax_invoice" + }, + "issue_type": { + "description": "발행 유형", + "type": "string", + "enum": [ + "normal", + "reverse", + "trustee" + ], + "example": "normal" + }, + "direction": { + "description": "방향 (매출/매입)", + "type": "string", + "enum": [ + "sales", + "purchases" + ], + "example": "sales" + }, + "supplier_corp_num": { + "description": "공급자 사업자번호", + "type": "string", + "maxLength": 10, + "minLength": 10, + "example": "1234567890" + }, + "supplier_corp_name": { + "description": "공급자 회사명", + "type": "string", + "maxLength": 200, + "example": "(주)공급사" + }, + "supplier_ceo_name": { + "description": "공급자 대표자명", + "type": "string", + "maxLength": 100, + "example": "홍길동" + }, + "supplier_addr": { + "description": "공급자 주소", + "type": "string", + "maxLength": 500, + "example": "서울시 강남구", + "nullable": true + }, + "supplier_biz_type": { + "description": "공급자 업태", + "type": "string", + "maxLength": 100, + "example": "서비스", + "nullable": true + }, + "supplier_biz_class": { + "description": "공급자 종목", + "type": "string", + "maxLength": 100, + "example": "소프트웨어", + "nullable": true + }, + "supplier_contact_id": { + "description": "공급자 담당자 이메일", + "type": "string", + "maxLength": 100, + "example": "supplier@test.com", + "nullable": true + }, + "buyer_corp_num": { + "description": "공급받는자 사업자번호", + "type": "string", + "maxLength": 10, + "minLength": 10, + "example": "0987654321" + }, + "buyer_corp_name": { + "description": "공급받는자 회사명", + "type": "string", + "maxLength": 200, + "example": "(주)구매사" + }, + "buyer_ceo_name": { + "description": "공급받는자 대표자명", + "type": "string", + "maxLength": 100, + "example": "김대표" + }, + "buyer_addr": { + "description": "공급받는자 주소", + "type": "string", + "maxLength": 500, + "example": "서울시 서초구", + "nullable": true + }, + "buyer_biz_type": { + "description": "공급받는자 업태", + "type": "string", + "maxLength": 100, + "example": "제조", + "nullable": true + }, + "buyer_biz_class": { + "description": "공급받는자 종목", + "type": "string", + "maxLength": 100, + "example": "전자제품", + "nullable": true + }, + "buyer_contact_id": { + "description": "공급받는자 담당자 이메일", + "type": "string", + "maxLength": 100, + "example": "buyer@test.com", + "nullable": true + }, + "issue_date": { + "description": "작성일자", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "format": "float", + "minimum": 0, + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "format": "float", + "minimum": 0, + "example": 100000 + }, + "items": { + "description": "품목 목록 (최대 99개)", + "type": "array", + "items": { + "properties": { + "date": { + "description": "거래일자", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "name": { + "description": "품목명", + "type": "string", + "maxLength": 200, + "example": "컨설팅 서비스" + }, + "spec": { + "description": "규격", + "type": "string", + "maxLength": 100, + "example": "월간", + "nullable": true + }, + "quantity": { + "description": "수량", + "type": "number", + "minimum": 0, + "example": 1 + }, + "unit_price": { + "description": "단가", + "type": "number", + "minimum": 0, + "example": 1000000 + }, + "supply_amount": { + "description": "공급가액", + "type": "number", + "minimum": 0, + "example": 1000000 + }, + "tax_amount": { + "description": "세액", + "type": "number", + "minimum": 0, + "example": 100000 + }, + "remark": { + "description": "비고", + "type": "string", + "maxLength": 200, + "example": "1월분", + "nullable": true + } + }, + "type": "object" + } + }, + "description": { + "description": "비고", + "type": "string", + "maxLength": 500, + "example": "월간 컨설팅 비용", + "nullable": true + } + }, + "type": "object" + }, + "TaxInvoiceCancelRequest": { + "description": "세금계산서 취소 요청", + "required": [ + "reason" + ], + "properties": { + "reason": { + "description": "취소 사유", + "type": "string", + "maxLength": 500, + "example": "거래 취소로 인한 세금계산서 취소" + } + }, + "type": "object" + }, + "TaxInvoiceBulkIssueRequest": { + "description": "세금계산서 일괄 발행 요청", + "required": [ + "ids" + ], + "properties": { + "ids": { + "description": "발행할 세금계산서 ID 목록 (최대 100개)", + "type": "array", + "items": { + "type": "integer", + "example": 1 + }, + "maxItems": 100, + "minItems": 1 + } + }, + "type": "object" + }, + "TaxInvoiceBulkIssueResponse": { + "description": "세금계산서 일괄 발행 응답", + "properties": { + "issued": { + "description": "발행 성공 건수", + "type": "integer", + "example": 8 + }, + "failed": { + "description": "발행 실패 건수", + "type": "integer", + "example": 2 + }, + "errors": { + "description": "실패 상세 (ID: 에러메시지)", + "type": "object", + "additionalProperties": { + "type": "string", + "example": "이미 발행된 세금계산서입니다." + } + } + }, + "type": "object" + }, + "TaxInvoiceSummary": { + "description": "세금계산서 요약 통계", + "properties": { + "by_direction": { + "description": "방향별 통계", + "properties": { + "sales": { + "properties": { + "count": { + "description": "매출 건수", + "type": "integer", + "example": 50 + }, + "supply_amount": { + "description": "공급가액 합계", + "type": "number", + "format": "float", + "example": 50000000 + }, + "tax_amount": { + "description": "세액 합계", + "type": "number", + "format": "float", + "example": 5000000 + }, + "total_amount": { + "description": "합계금액", + "type": "number", + "format": "float", + "example": 55000000 + } + }, + "type": "object" + }, + "purchases": { + "properties": { + "count": { + "description": "매입 건수", + "type": "integer", + "example": 30 + }, + "supply_amount": { + "description": "공급가액 합계", + "type": "number", + "format": "float", + "example": 30000000 + }, + "tax_amount": { + "description": "세액 합계", + "type": "number", + "format": "float", + "example": 3000000 + }, + "total_amount": { + "description": "합계금액", + "type": "number", + "format": "float", + "example": 33000000 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "by_status": { + "description": "상태별 건수", + "properties": { + "draft": { + "description": "임시저장 건수", + "type": "integer", + "example": 5 + }, + "issued": { + "description": "발행완료 건수", + "type": "integer", + "example": 30 + }, + "sent": { + "description": "국세청 전송 건수", + "type": "integer", + "example": 40 + }, + "cancelled": { + "description": "취소 건수", + "type": "integer", + "example": 3 + }, + "failed": { + "description": "발행실패 건수", + "type": "integer", + "example": 2 + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Tenant": { + "description": "테넌트 상세 정보", + "required": [ + "id", + "company_name" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "company_name": { + "type": "string", + "example": "(주)경동기업" + }, + "code": { + "type": "string", + "example": "KDCOM" + }, + "email": { + "type": "string", + "example": "kd5130@naver.com" + }, + "phone": { + "type": "string", + "example": "01083935130" + }, + "address": { + "type": "string", + "example": "경기도 김포시 통진읍 옹정로 45-22" + }, + "business_num": { + "type": "string", + "example": "1398700333" + }, + "corp_reg_no": { + "type": "string", + "example": null, + "nullable": true + }, + "ceo_name": { + "type": "string", + "example": "이대표" + }, + "homepage": { + "type": "string", + "example": null, + "nullable": true + }, + "fax": { + "type": "string", + "example": null, + "nullable": true + }, + "logo": { + "type": "string", + "example": null, + "nullable": true + }, + "admin_memo": { + "type": "string", + "example": null, + "nullable": true + }, + "options": { + "type": "string", + "example": null, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-07-16 18:28:41" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-07-25 23:13:06" + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "TenantPagination": { + "description": "라라벨 LengthAwarePaginator 기본 구조", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TenantBrief" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/tenants/list?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 1 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/tenants/list?page=1" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/tenants/list" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 3 + }, + "total": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + }, + "TenantCreateRequest": { + "required": [ + "company_name" + ], + "properties": { + "company_name": { + "description": "회사명", + "type": "string", + "example": "(주)신규기업" + }, + "email": { + "description": "대표 이메일", + "type": "string", + "example": "newcompany@example.com", + "nullable": true + }, + "phone": { + "description": "대표 연락처", + "type": "string", + "example": "01012345678", + "nullable": true + }, + "address": { + "description": "주소", + "type": "string", + "example": "서울시 강남구", + "nullable": true + }, + "business_num": { + "description": "사업자등록번호", + "type": "string", + "example": "1234567890", + "nullable": true + }, + "ceo_name": { + "description": "대표자명", + "type": "string", + "example": "김대표", + "nullable": true + } + }, + "type": "object" + }, + "TenantUpdateRequest": { + "properties": { + "tenant_id": { + "description": "수정 대상 테넌트 ID", + "type": "integer", + "example": 1 + }, + "company_name": { + "description": "회사명", + "type": "string", + "example": "(주)신규기업" + }, + "email": { + "description": "대표 이메일", + "type": "string", + "example": "newcompany@example.com" + }, + "phone": { + "description": "대표 연락처", + "type": "string", + "example": "01012345678" + }, + "address": { + "description": "주소", + "type": "string", + "example": "서울시 강남구", + "nullable": true + }, + "business_num": { + "description": "사업자등록번호", + "type": "string", + "example": "1234567890", + "nullable": true + }, + "ceo_name": { + "description": "대표자명", + "type": "string", + "example": "김대표", + "nullable": true + } + }, + "type": "object" + }, + "TenantFieldSetting": { + "properties": { + "field_key": { + "type": "string", + "example": "product_name_required" + }, + "field_value": { + "type": "string", + "example": "true" + }, + "source": { + "description": "global 또는 tenant", + "type": "string", + "example": "tenant" + } + }, + "type": "object" + }, + "TenantFieldSettingBulkRequest": { + "properties": { + "fields": { + "type": "array", + "items": { + "properties": { + "field_key": { + "type": "string", + "example": "product_name_required" + }, + "field_value": { + "type": "string", + "example": "true" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "TenantSetting": { + "required": [ + "id", + "tenant_id", + "setting_group", + "setting_key" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 287 + }, + "setting_group": { + "type": "string", + "example": "stock" + }, + "setting_key": { + "type": "string", + "example": "stock_item_types" + }, + "setting_value": { + "type": "object", + "example": [ + "RM", + "SM", + "CS", + "PT", + "SF" + ] + }, + "description": { + "type": "string", + "example": "재고관리 대상 품목유형", + "nullable": true + }, + "updated_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "TenantSettingStoreRequest": { + "required": [ + "group", + "key", + "value" + ], + "properties": { + "group": { + "description": "설정 그룹", + "type": "string", + "maxLength": 50, + "example": "stock" + }, + "key": { + "description": "설정 키", + "type": "string", + "maxLength": 100, + "example": "stock_item_types" + }, + "value": { + "description": "설정 값 (JSON)", + "type": "object", + "example": [ + "RM", + "SM", + "CS", + "PT", + "SF" + ] + }, + "description": { + "description": "설정 설명", + "type": "string", + "maxLength": 255, + "example": "재고관리 대상 품목유형", + "nullable": true + } + }, + "type": "object" + }, + "TenantSettingBulkRequest": { + "required": [ + "group", + "settings" + ], + "properties": { + "group": { + "description": "설정 그룹", + "type": "string", + "maxLength": 50, + "example": "stock" + }, + "settings": { + "type": "array", + "items": { + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "example": "stock_item_types" + }, + "value": { + "type": "object", + "example": [ + "RM", + "SM", + "CS" + ] + }, + "description": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "TenantStatField": { + "required": [ + "id", + "tenant_id", + "target_table", + "field_key", + "field_name", + "field_type" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "target_table": { + "type": "string", + "example": "products" + }, + "field_key": { + "type": "string", + "example": "margin_rate" + }, + "field_name": { + "type": "string", + "example": "마진율(%)" + }, + "field_type": { + "type": "string", + "example": "decimal" + }, + "aggregation_types": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "avg", + "min", + "max" + ], + "nullable": true + }, + "is_critical": { + "type": "boolean", + "example": true + }, + "display_order": { + "type": "integer", + "example": 0 + }, + "description": { + "type": "string", + "example": "제품 마진율 통계", + "nullable": true + }, + "created_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "updated_by": { + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "example": "2025-11-14 10:00:00" + }, + "updated_at": { + "type": "string", + "example": "2025-11-14 10:10:00" + } + }, + "type": "object" + }, + "TenantStatFieldPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TenantStatField" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/tenant-stat-fields?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 2 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/tenant-stat-fields?page=2" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": "/api/v1/tenant-stat-fields?page=2", + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/tenant-stat-fields" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 9 + } + }, + "type": "object" + }, + "TenantStatFieldCreateRequest": { + "required": [ + "target_table", + "field_key", + "field_name", + "field_type" + ], + "properties": { + "target_table": { + "type": "string", + "maxLength": 50, + "example": "products" + }, + "field_key": { + "type": "string", + "maxLength": 100, + "example": "processing_cost" + }, + "field_name": { + "type": "string", + "maxLength": 100, + "example": "가공비(원)" + }, + "field_type": { + "type": "string", + "maxLength": 20, + "example": "decimal" + }, + "aggregation_types": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "avg", + "sum", + "min", + "max", + "count" + ] + }, + "example": [ + "avg", + "sum" + ], + "nullable": true + }, + "is_critical": { + "type": "boolean", + "example": false, + "nullable": true + }, + "display_order": { + "type": "integer", + "example": 0, + "nullable": true + }, + "description": { + "type": "string", + "example": "제품별 가공비 통계", + "nullable": true + } + }, + "type": "object" + }, + "TenantStatFieldUpdateRequest": { + "properties": { + "target_table": { + "type": "string", + "maxLength": 50, + "example": "products" + }, + "field_key": { + "type": "string", + "maxLength": 100, + "example": "processing_cost" + }, + "field_name": { + "type": "string", + "maxLength": 100, + "example": "가공비(원)" + }, + "field_type": { + "type": "string", + "maxLength": 20, + "example": "decimal" + }, + "aggregation_types": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "avg", + "sum", + "min", + "max", + "count" + ] + }, + "nullable": true + }, + "is_critical": { + "type": "boolean", + "example": true, + "nullable": true + }, + "display_order": { + "type": "integer", + "example": 5, + "nullable": true + }, + "description": { + "type": "string", + "example": "제품별 가공비 통계 (일일 집계)", + "nullable": true + } + }, + "type": "object" + }, + "TenantStatFieldReorderRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "display_order": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "TenantStatFieldBulkUpsertRequest": { + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "items": { + "properties": { + "id": { + "description": "수정 시 ID 필수, 신규 시 null", + "type": "integer", + "example": null, + "nullable": true + }, + "target_table": { + "type": "string", + "maxLength": 50, + "example": "products" + }, + "field_key": { + "type": "string", + "maxLength": 100, + "example": "margin_rate" + }, + "field_name": { + "type": "string", + "maxLength": 100, + "example": "마진율(%)" + }, + "field_type": { + "type": "string", + "maxLength": 20, + "example": "decimal" + }, + "aggregation_types": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "is_critical": { + "type": "boolean", + "example": true, + "nullable": true + }, + "display_order": { + "type": "integer", + "example": 0, + "nullable": true + }, + "description": { + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "TodayIssueItem": { + "description": "오늘의 이슈 항목", + "required": [ + "id", + "badge", + "content", + "time" + ], + "properties": { + "id": { + "description": "항목 고유 ID", + "type": "string", + "example": "order_123" + }, + "badge": { + "description": "이슈 카테고리 뱃지", + "type": "string", + "enum": [ + "수주 성공", + "주식 이슈", + "직정 제고", + "지출예상내역서", + "세금 신고", + "결재 요청", + "기타" + ], + "example": "수주 성공" + }, + "content": { + "description": "이슈 내용", + "type": "string", + "example": "A전자 신규 수주 450,000,000원 확정" + }, + "time": { + "description": "상대 시간", + "type": "string", + "example": "10분 전" + }, + "date": { + "description": "날짜 (ISO 형식)", + "type": "string", + "format": "date", + "example": "2026-01-20" + }, + "needsApproval": { + "description": "승인/반려 버튼 표시 여부", + "type": "boolean", + "example": false + }, + "path": { + "description": "클릭 시 이동할 경로", + "type": "string", + "example": "/sales/order-management-sales" + } + }, + "type": "object" + }, + "TodayIssueSummaryResponse": { + "description": "오늘의 이슈 리스트 응답", + "properties": { + "items": { + "description": "이슈 항목 리스트", + "type": "array", + "items": { + "$ref": "#/components/schemas/TodayIssueItem" + } + }, + "total_count": { + "description": "전체 이슈 건수", + "type": "integer", + "example": 25 + } + }, + "type": "object" + }, + "TodayIssueUnreadItem": { + "description": "읽지 않은 이슈 항목 (헤더 알림용)", + "required": [ + "id", + "badge", + "content", + "time", + "created_at" + ], + "properties": { + "id": { + "description": "이슈 고유 ID", + "type": "integer", + "example": 123 + }, + "badge": { + "description": "이슈 카테고리 뱃지", + "type": "string", + "enum": [ + "수주등록", + "추심이슈", + "안전재고", + "지출 승인대기", + "세금 신고", + "결재 요청", + "신규거래처" + ], + "example": "수주등록" + }, + "notification_type": { + "description": "알림 설정 타입", + "type": "string", + "enum": [ + "sales_order", + "new_vendor", + "approval_request", + "bad_debt", + "safety_stock", + "expected_expense", + "vat_report" + ], + "example": "sales_order" + }, + "content": { + "description": "이슈 내용", + "type": "string", + "example": "대한건설 신규 수주 1억 2천만원 등록" + }, + "path": { + "description": "클릭 시 이동할 경로", + "type": "string", + "example": "/sales/order-management-sales", + "nullable": true + }, + "needs_approval": { + "description": "승인/반려 버튼 표시 여부", + "type": "boolean", + "example": false + }, + "time": { + "description": "상대 시간", + "type": "string", + "example": "10분 전" + }, + "created_at": { + "description": "생성 일시 (ISO 8601)", + "type": "string", + "format": "date-time", + "example": "2026-01-21T10:30:00+09:00" + } + }, + "type": "object" + }, + "TodayIssueUnreadResponse": { + "description": "읽지 않은 이슈 목록 응답", + "properties": { + "items": { + "description": "읽지 않은 이슈 항목 리스트", + "type": "array", + "items": { + "$ref": "#/components/schemas/TodayIssueUnreadItem" + } + }, + "total": { + "description": "읽지 않은 전체 이슈 건수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "TodayIssueUnreadCountResponse": { + "description": "읽지 않은 이슈 개수 응답", + "properties": { + "count": { + "description": "읽지 않은 이슈 건수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "TodayIssueMarkAllReadResponse": { + "description": "모든 이슈 읽음 처리 응답", + "properties": { + "count": { + "description": "읽음 처리된 이슈 건수", + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "Member": { + "description": "회원 기본 정보", + "required": [ + "id", + "user_id", + "name", + "email" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "user_id": { + "type": "string", + "example": "hamss" + }, + "phone": { + "type": "string", + "example": "010-4820-9104", + "nullable": true + }, + "options": { + "type": "string", + "example": null, + "nullable": true + }, + "name": { + "type": "string", + "example": "Kent" + }, + "email": { + "type": "string", + "example": "codebridge@gmail.com" + }, + "email_verified_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + }, + "last_login_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + }, + "current_team_id": { + "type": "integer", + "example": null, + "nullable": true + }, + "profile_photo_path": { + "type": "string", + "example": null, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2025-07-16 18:28:41" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2025-07-25 23:13:06" + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "MemberPagination": { + "description": "라라벨 LengthAwarePaginator 기본 구조", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Member" + } + }, + "first_page_url": { + "type": "string", + "example": "/api/v1/users/index?page=1" + }, + "from": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 1 + }, + "last_page_url": { + "type": "string", + "example": "/api/v1/users/index?page=1" + }, + "links": { + "type": "array", + "items": { + "properties": { + "url": { + "type": "string", + "example": null, + "nullable": true + }, + "label": { + "type": "string", + "example": "« Previous" + }, + "active": { + "type": "boolean", + "example": false + } + }, + "type": "object" + } + }, + "next_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "path": { + "type": "string", + "example": "/api/v1/users/index" + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "prev_page_url": { + "type": "string", + "example": null, + "nullable": true + }, + "to": { + "type": "integer", + "example": 3 + }, + "total": { + "type": "integer", + "example": 3 + } + }, + "type": "object" + }, + "TenantBrief": { + "description": "간단 테넌트 정보", + "required": [ + "id", + "company_name" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "company_name": { + "type": "string", + "example": "(주)경동기업" + }, + "code": { + "type": "string", + "example": "KDCOM" + }, + "email": { + "type": "string", + "example": "kd5130@naver.com" + }, + "phone": { + "type": "string", + "example": "01083935130" + }, + "address": { + "type": "string", + "example": "경기도 김포시 통진읍 옹정로 45-22" + }, + "business_num": { + "type": "string", + "example": "1398700333" + }, + "corp_reg_no": { + "type": "string", + "example": null, + "nullable": true + }, + "ceo_name": { + "type": "string", + "example": "이대표" + }, + "homepage": { + "type": "string", + "example": null, + "nullable": true + }, + "fax": { + "type": "string", + "example": null, + "nullable": true + }, + "logo": { + "type": "string", + "example": null, + "nullable": true + }, + "admin_memo": { + "type": "string", + "example": null, + "nullable": true + }, + "options": { + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "MeResponseData": { + "description": "내 정보 + 테넌트 정보", + "properties": { + "user": { + "$ref": "#/components/schemas/Member" + }, + "tenant": { + "$ref": "#/components/schemas/TenantBrief" + } + }, + "type": "object" + }, + "UserUpdateRequest": { + "description": "사용자 정보 수정 요청", + "properties": { + "name": { + "type": "string", + "maxLength": 100, + "example": "홍길동" + }, + "phone": { + "type": "string", + "maxLength": 20, + "example": "010-1234-5678", + "nullable": true + }, + "email": { + "type": "string", + "maxLength": 100, + "example": "user@example.com" + } + }, + "type": "object" + }, + "PasswordChangeRequest": { + "description": "비밀번호 변경 요청", + "required": [ + "current_password", + "new_password", + "new_password_confirmation" + ], + "properties": { + "current_password": { + "type": "string", + "format": "password", + "example": "current123" + }, + "new_password": { + "type": "string", + "format": "password", + "minLength": 8, + "example": "newpass123" + }, + "new_password_confirmation": { + "type": "string", + "format": "password", + "example": "newpass123" + } + }, + "type": "object" + }, + "SwitchTenantRequest": { + "description": "테넌트 전환 요청", + "required": [ + "tenant_id" + ], + "properties": { + "tenant_id": { + "type": "integer", + "example": 2 + } + }, + "type": "object" + }, + "UserInvitation": { + "required": [ + "id", + "tenant_id", + "email", + "token", + "status", + "invited_by", + "expires_at" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "email": { + "type": "string", + "format": "email", + "example": "user@example.com" + }, + "role_id": { + "type": "integer", + "example": 2, + "nullable": true + }, + "message": { + "type": "string", + "example": "회사에 합류해 주세요!", + "nullable": true + }, + "token": { + "type": "string", + "example": "abc123..." + }, + "status": { + "type": "string", + "enum": [ + "pending", + "accepted", + "expired", + "cancelled" + ], + "example": "pending" + }, + "status_label": { + "type": "string", + "example": "대기중" + }, + "invited_by": { + "type": "integer", + "example": 1 + }, + "expires_at": { + "type": "string", + "format": "date-time" + }, + "accepted_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "role": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + }, + "inviter": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "UserInvitationPagination": { + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserInvitation" + } + }, + "current_page": { + "type": "integer", + "example": 1 + }, + "last_page": { + "type": "integer", + "example": 5 + }, + "per_page": { + "type": "integer", + "example": 20 + }, + "total": { + "type": "integer", + "example": 100 + } + }, + "type": "object" + }, + "InviteUserRequest": { + "required": [ + "email" + ], + "properties": { + "email": { + "description": "초대할 사용자 이메일", + "type": "string", + "format": "email", + "example": "newuser@example.com" + }, + "role": { + "description": "부여할 역할 (role 또는 role_id 중 하나만 사용)", + "type": "string", + "enum": [ + "admin", + "manager", + "user" + ], + "example": "user", + "nullable": true + }, + "role_id": { + "description": "부여할 역할 ID (role 또는 role_id 중 하나만 사용)", + "type": "integer", + "example": 2, + "nullable": true + }, + "message": { + "description": "초대 메시지", + "type": "string", + "example": "SAM 시스템에 합류해 주세요!", + "nullable": true + }, + "expires_days": { + "description": "만료 기간(일)", + "type": "integer", + "maximum": 30, + "minimum": 1, + "example": 7, + "nullable": true + } + }, + "type": "object" + }, + "AcceptInvitationRequest": { + "required": [ + "name", + "password", + "password_confirmation" + ], + "properties": { + "name": { + "description": "사용자 이름", + "type": "string", + "example": "홍길동" + }, + "password": { + "description": "비밀번호 (8자 이상)", + "type": "string", + "format": "password", + "example": "password123" + }, + "password_confirmation": { + "description": "비밀번호 확인", + "type": "string", + "format": "password", + "example": "password123" + }, + "phone": { + "description": "연락처", + "type": "string", + "example": "010-1234-5678", + "nullable": true + } + }, + "type": "object" + }, + "UserRoleGrantRequest": { + "description": "사용자에게 역할 부여. role_names 또는 role_ids 중 하나 사용.", + "type": "object", + "oneOf": [ + { + "required": [ + "role_names" + ], + "properties": { + "role_names": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "menu-manager", + "readonly" + ] + } + }, + "type": "object" + }, + { + "required": [ + "role_ids" + ], + "properties": { + "role_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1, + 2 + ] + } + }, + "type": "object" + } + ] + }, + "UserRoleRevokeRequest": { + "description": "사용자로부터 역할 회수. role_names 또는 role_ids 중 하나 사용.", + "type": "object", + "oneOf": [ + { + "required": [ + "role_names" + ], + "properties": { + "role_names": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "readonly" + ] + } + }, + "type": "object" + }, + { + "required": [ + "role_ids" + ], + "properties": { + "role_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 2 + ] + } + }, + "type": "object" + } + ] + }, + "UserRoleSyncRequest": { + "description": "사용자의 역할을 전달된 목록으로 완전히 교체. role_names 또는 role_ids 중 하나 사용.", + "type": "object", + "oneOf": [ + { + "required": [ + "role_names" + ], + "properties": { + "role_names": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "menu-manager" + ] + } + }, + "type": "object" + }, + { + "required": [ + "role_ids" + ], + "properties": { + "role_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "example": [ + 1 + ] + } + }, + "type": "object" + } + ] + }, + "VatAmountCard": { + "description": "부가세 금액 카드", + "required": [ + "id", + "label", + "amount" + ], + "properties": { + "id": { + "description": "카드 ID", + "type": "string", + "example": "vat_sales_tax" + }, + "label": { + "description": "카드 라벨", + "type": "string", + "example": "매출세액" + }, + "amount": { + "description": "금액", + "type": "integer", + "example": 3050000000 + }, + "subLabel": { + "description": "부가 라벨 (환급 등)", + "type": "string", + "example": "환급", + "nullable": true + }, + "unit": { + "description": "단위 (건, 원 등)", + "type": "string", + "example": "건", + "nullable": true + } + }, + "type": "object" + }, + "VatHighlightItem": { + "description": "체크포인트 하이라이트 아이템", + "required": [ + "text", + "color" + ], + "properties": { + "text": { + "description": "하이라이트 텍스트", + "type": "string", + "example": "2026년 1기 예정신고 기준, 예상 납부세액은 110,100,000원입니다." + }, + "color": { + "description": "색상 (red, blue, green 등)", + "type": "string", + "example": "red" + } + }, + "type": "object" + }, + "VatCheckPoint": { + "description": "부가세 체크포인트", + "required": [ + "id", + "type", + "message" + ], + "properties": { + "id": { + "description": "체크포인트 ID", + "type": "string", + "example": "vat_cp_payment" + }, + "type": { + "description": "타입 (success, warning, error)", + "type": "string", + "example": "success" + }, + "message": { + "description": "메시지", + "type": "string", + "example": "2026년 1기 예정신고 기준, 예상 납부세액은 110,100,000원입니다. 전기 대비 12.9% 증가했습니다." + }, + "highlights": { + "description": "하이라이트 아이템 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/VatHighlightItem" + } + } + }, + "type": "object" + }, + "VatSummaryResponse": { + "description": "부가세 현황 요약 응답", + "required": [ + "cards", + "check_points" + ], + "properties": { + "cards": { + "description": "금액 카드 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/VatAmountCard" + } + }, + "check_points": { + "description": "체크포인트 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/VatCheckPoint" + } + } + }, + "type": "object" + }, + "VendorLedgerItem": { + "description": "거래처원장 리스트 항목", + "properties": { + "id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "거래처명", + "type": "string", + "example": "ABC 주식회사" + }, + "sales_payment_day": { + "description": "결제일", + "type": "string", + "example": "25일", + "nullable": true + }, + "period_sales": { + "description": "기간 내 매출", + "type": "number", + "format": "float", + "example": 10000000 + }, + "period_collection": { + "description": "기간 내 수금", + "type": "number", + "format": "float", + "example": 8000000 + }, + "carryover_sales": { + "description": "이월 매출", + "type": "number", + "format": "float", + "example": 5000000 + }, + "carryover_deposits": { + "description": "이월 수금", + "type": "number", + "format": "float", + "example": 3000000 + } + }, + "type": "object" + }, + "VendorLedgerSummary": { + "description": "거래처원장 요약 통계", + "properties": { + "carryover_balance": { + "description": "이월잔액", + "type": "number", + "format": "float", + "example": 2000000 + }, + "total_sales": { + "description": "총 매출", + "type": "number", + "format": "float", + "example": 10000000 + }, + "total_collection": { + "description": "총 수금", + "type": "number", + "format": "float", + "example": 8000000 + }, + "balance": { + "description": "현재 잔액", + "type": "number", + "format": "float", + "example": 4000000 + } + }, + "type": "object" + }, + "VendorLedgerTransaction": { + "description": "거래처원장 거래 내역", + "properties": { + "id": { + "description": "거래 ID", + "type": "integer", + "example": 1 + }, + "date": { + "description": "거래일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "type": { + "description": "거래 유형", + "type": "string", + "enum": [ + "sales", + "collection", + "note" + ], + "example": "sales" + }, + "description": { + "description": "적요", + "type": "string", + "example": "제품 납품" + }, + "sales_amount": { + "description": "매출 금액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "collection_amount": { + "description": "수금 금액", + "type": "number", + "format": "float", + "example": 0 + }, + "balance": { + "description": "잔액", + "type": "number", + "format": "float", + "example": 1000000 + }, + "reference_id": { + "description": "참조 ID", + "type": "integer", + "example": 1 + }, + "reference_type": { + "description": "참조 타입", + "type": "string", + "enum": [ + "sale", + "deposit", + "bill" + ], + "example": "sale" + }, + "has_action": { + "description": "작업 버튼 표시 여부", + "type": "boolean", + "example": false + }, + "is_highlighted": { + "description": "하이라이트 여부", + "type": "boolean", + "example": true + }, + "is_parenthesis": { + "description": "괄호 표시 여부", + "type": "boolean", + "example": false + }, + "note_info": { + "description": "어음 정보", + "type": "string", + "example": "2025-02-15", + "nullable": true + } + }, + "type": "object" + }, + "VendorLedgerClient": { + "description": "거래처 정보", + "properties": { + "id": { + "description": "거래처 ID", + "type": "integer", + "example": 1 + }, + "name": { + "description": "거래처명", + "type": "string", + "example": "ABC 주식회사" + }, + "business_number": { + "description": "사업자등록번호", + "type": "string", + "example": "123-45-67890", + "nullable": true + }, + "representative_name": { + "description": "대표자", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "phone": { + "description": "전화번호", + "type": "string", + "example": "02-1234-5678", + "nullable": true + }, + "mobile": { + "description": "휴대전화", + "type": "string", + "example": "010-1234-5678", + "nullable": true + }, + "fax": { + "description": "팩스", + "type": "string", + "example": "02-1234-5679", + "nullable": true + }, + "email": { + "description": "이메일", + "type": "string", + "example": "contact@example.com", + "nullable": true + }, + "address": { + "description": "주소", + "type": "string", + "example": "서울시 강남구", + "nullable": true + } + }, + "type": "object" + }, + "VendorLedgerDetail": { + "description": "거래처원장 상세", + "properties": { + "client": { + "$ref": "#/components/schemas/VendorLedgerClient" + }, + "period": { + "properties": { + "start_date": { + "type": "string", + "format": "date", + "example": "2025-01-01" + }, + "end_date": { + "type": "string", + "format": "date", + "example": "2025-12-31" + } + }, + "type": "object" + }, + "carryover_balance": { + "description": "이월잔액", + "type": "number", + "format": "float", + "example": 2000000 + }, + "total_sales": { + "description": "총 매출", + "type": "number", + "format": "float", + "example": 10000000 + }, + "total_collection": { + "description": "총 수금", + "type": "number", + "format": "float", + "example": 8000000 + }, + "balance": { + "description": "현재 잔액", + "type": "number", + "format": "float", + "example": 4000000 + }, + "transactions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VendorLedgerTransaction" + } + } + }, + "type": "object" + }, + "VendorLedgerPagination": { + "description": "거래처원장 목록 페이지네이션", + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VendorLedgerItem" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "last_page_url": { + "type": "string" + }, + "next_page_url": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string" + }, + "per_page": { + "type": "integer" + }, + "prev_page_url": { + "type": "string", + "nullable": true + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + }, + "type": "object" + }, + "WelfareAmountCard": { + "description": "복리후생비 금액 카드", + "required": [ + "id", + "label", + "amount" + ], + "properties": { + "id": { + "description": "카드 ID", + "type": "string", + "example": "wf_annual_limit" + }, + "label": { + "description": "카드 라벨", + "type": "string", + "example": "당해년도 복리후생비 한도" + }, + "amount": { + "description": "금액", + "type": "integer", + "example": 30123000 + }, + "subLabel": { + "description": "부가 라벨", + "type": "string", + "example": null, + "nullable": true + }, + "unit": { + "description": "단위", + "type": "string", + "example": null, + "nullable": true + } + }, + "type": "object" + }, + "WelfareHighlightItem": { + "description": "체크포인트 하이라이트 아이템", + "required": [ + "text", + "color" + ], + "properties": { + "text": { + "description": "하이라이트 텍스트", + "type": "string", + "example": "1인당 월 복리후생비 20만원" + }, + "color": { + "description": "색상 (red, green, orange 등)", + "type": "string", + "example": "green" + } + }, + "type": "object" + }, + "WelfareCheckPoint": { + "description": "복리후생비 체크포인트", + "required": [ + "id", + "type", + "message" + ], + "properties": { + "id": { + "description": "체크포인트 ID", + "type": "string", + "example": "wf_cp_normal" + }, + "type": { + "description": "타입 (success, warning, error)", + "type": "string", + "example": "success" + }, + "message": { + "description": "메시지", + "type": "string", + "example": "1인당 월 복리후생비 20만원. 업계 평균(15~25만원) 내 정상 운영 중입니다." + }, + "highlights": { + "description": "하이라이트 아이템 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/WelfareHighlightItem" + } + } + }, + "type": "object" + }, + "WelfareSummaryResponse": { + "description": "복리후생비 현황 요약 응답", + "required": [ + "cards", + "check_points" + ], + "properties": { + "cards": { + "description": "금액 카드 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/WelfareAmountCard" + } + }, + "check_points": { + "description": "체크포인트 목록", + "type": "array", + "items": { + "$ref": "#/components/schemas/WelfareCheckPoint" + } + } + }, + "type": "object" + }, + "WelfareDetailSummary": { + "description": "복리후생비 상세 요약", + "required": [ + "annual_account", + "annual_limit", + "annual_used", + "annual_remaining", + "quarterly_limit", + "quarterly_remaining", + "quarterly_used", + "quarterly_exceeded" + ], + "properties": { + "annual_account": { + "description": "당해년도 복리후생비 계정", + "type": "integer", + "example": 3123000 + }, + "annual_limit": { + "description": "당해년도 복리후생비 한도", + "type": "integer", + "example": 48000000 + }, + "annual_used": { + "description": "당해년도 복리후생비 사용", + "type": "integer", + "example": 6000000 + }, + "annual_remaining": { + "description": "당해년도 잔여한도", + "type": "integer", + "example": 42000000 + }, + "quarterly_limit": { + "description": "분기 복리후생비 총 한도", + "type": "integer", + "example": 12000000 + }, + "quarterly_remaining": { + "description": "분기 복리후생비 잔여한도", + "type": "integer", + "example": 11000000 + }, + "quarterly_used": { + "description": "분기 복리후생비 사용금액", + "type": "integer", + "example": 1000000 + }, + "quarterly_exceeded": { + "description": "분기 복리후생비 초과 금액", + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "WelfareMonthlyUsage": { + "description": "월별 사용 추이 항목", + "required": [ + "month", + "amount" + ], + "properties": { + "month": { + "description": "월 (1-12)", + "type": "integer", + "example": 1 + }, + "amount": { + "description": "사용 금액", + "type": "integer", + "example": 1500000 + } + }, + "type": "object" + }, + "WelfareCategoryDistribution": { + "description": "항목별 분포", + "required": [ + "category", + "label", + "amount", + "ratio" + ], + "properties": { + "category": { + "description": "카테고리 코드", + "type": "string", + "example": "meal" + }, + "label": { + "description": "카테고리 라벨", + "type": "string", + "example": "식비" + }, + "amount": { + "description": "사용 금액", + "type": "integer", + "example": 55000000 + }, + "ratio": { + "description": "비율 (%)", + "type": "number", + "format": "float", + "example": 55 + } + }, + "type": "object" + }, + "WelfareTransaction": { + "description": "사용 내역 항목", + "required": [ + "id", + "card_name", + "user_name", + "expense_date", + "vendor_name", + "amount", + "sub_type", + "sub_type_label" + ], + "properties": { + "id": { + "description": "거래 ID", + "type": "integer", + "example": 1 + }, + "card_name": { + "description": "카드명", + "type": "string", + "example": "카드 *1234" + }, + "user_name": { + "description": "사용자명", + "type": "string", + "example": "홍길동" + }, + "expense_date": { + "description": "사용일자", + "type": "string", + "example": "2025-12-12 12:12" + }, + "vendor_name": { + "description": "가맹점명", + "type": "string", + "example": "스타벅스" + }, + "amount": { + "description": "사용금액", + "type": "integer", + "example": 1000000 + }, + "sub_type": { + "description": "항목 코드", + "type": "string", + "example": "meal" + }, + "sub_type_label": { + "description": "항목명", + "type": "string", + "example": "식비" + } + }, + "type": "object" + }, + "WelfareCalculation": { + "description": "복리후생비 계산 정보", + "required": [ + "type", + "employee_count", + "annual_limit" + ], + "properties": { + "type": { + "description": "계산 방식", + "type": "string", + "enum": [ + "fixed", + "ratio" + ], + "example": "fixed" + }, + "employee_count": { + "description": "직원 수", + "type": "integer", + "example": 20 + }, + "monthly_amount": { + "description": "1인당 월 정액 (fixed 방식)", + "type": "integer", + "example": 200000, + "nullable": true + }, + "total_salary": { + "description": "연봉 총액 (ratio 방식)", + "type": "integer", + "example": 1000000000, + "nullable": true + }, + "ratio": { + "description": "비율 (%, ratio 방식)", + "type": "number", + "format": "float", + "example": 5, + "nullable": true + }, + "annual_limit": { + "description": "당해년도 복리후생비 총 한도", + "type": "integer", + "example": 48000000 + } + }, + "type": "object" + }, + "WelfareQuarterlyStatus": { + "description": "분기별 현황", + "required": [ + "quarter", + "limit", + "carryover", + "used", + "remaining", + "exceeded" + ], + "properties": { + "quarter": { + "description": "분기 (1-4)", + "type": "integer", + "example": 1 + }, + "limit": { + "description": "한도금액", + "type": "integer", + "example": 12000000 + }, + "carryover": { + "description": "이월금액", + "type": "integer", + "example": 0 + }, + "used": { + "description": "사용금액", + "type": "integer", + "example": 1000000 + }, + "remaining": { + "description": "잔여한도", + "type": "integer", + "example": 11000000 + }, + "exceeded": { + "description": "초과금액", + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "WelfareDetailResponse": { + "description": "복리후생비 상세 응답 (모달용)", + "required": [ + "summary", + "monthly_usage", + "category_distribution", + "transactions", + "calculation", + "quarterly" + ], + "properties": { + "summary": { + "$ref": "#/components/schemas/WelfareDetailSummary" + }, + "monthly_usage": { + "description": "월별 사용 추이", + "type": "array", + "items": { + "$ref": "#/components/schemas/WelfareMonthlyUsage" + } + }, + "category_distribution": { + "description": "항목별 분포", + "type": "array", + "items": { + "$ref": "#/components/schemas/WelfareCategoryDistribution" + } + }, + "transactions": { + "description": "사용 내역", + "type": "array", + "items": { + "$ref": "#/components/schemas/WelfareTransaction" + } + }, + "calculation": { + "$ref": "#/components/schemas/WelfareCalculation" + }, + "quarterly": { + "description": "분기별 현황", + "type": "array", + "items": { + "$ref": "#/components/schemas/WelfareQuarterlyStatus" + } + } + }, + "type": "object" + }, + "Withdrawal": { + "description": "출금 정보", + "properties": { + "id": { + "description": "출금 ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "withdrawal_date": { + "description": "출금일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "description": "비회원 거래처명", + "type": "string", + "example": "홍길동", + "nullable": true + }, + "bank_account_id": { + "description": "출금 계좌 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 500000 + }, + "payment_method": { + "description": "결제수단", + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ], + "example": "transfer" + }, + "account_code": { + "description": "계정과목", + "type": "string", + "example": "501", + "nullable": true + }, + "description": { + "description": "적요", + "type": "string", + "example": "사무용품 구매", + "nullable": true + }, + "reference_type": { + "description": "참조 유형", + "type": "string", + "example": "purchase", + "nullable": true + }, + "reference_id": { + "description": "참조 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client": { + "description": "거래처 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "name": { + "type": "string", + "example": "(주)테스트" + } + }, + "type": "object", + "nullable": true + }, + "bank_account": { + "description": "계좌 정보", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "bank_name": { + "type": "string", + "example": "국민은행" + }, + "account_name": { + "type": "string", + "example": "법인통장" + } + }, + "type": "object", + "nullable": true + }, + "created_by": { + "description": "생성자 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "WithdrawalCreateRequest": { + "description": "출금 등록 요청", + "required": [ + "withdrawal_date", + "amount", + "payment_method" + ], + "properties": { + "withdrawal_date": { + "description": "출금일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "description": "비회원 거래처명", + "type": "string", + "maxLength": 100, + "example": "홍길동", + "nullable": true + }, + "bank_account_id": { + "description": "출금 계좌 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 500000 + }, + "payment_method": { + "description": "결제수단", + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ], + "example": "transfer" + }, + "account_code": { + "description": "계정과목", + "type": "string", + "maxLength": 20, + "example": "501", + "nullable": true + }, + "description": { + "description": "적요", + "type": "string", + "maxLength": 1000, + "example": "사무용품 구매", + "nullable": true + }, + "reference_type": { + "description": "참조 유형", + "type": "string", + "maxLength": 50, + "example": "purchase", + "nullable": true + }, + "reference_id": { + "description": "참조 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "WithdrawalUpdateRequest": { + "description": "출금 수정 요청", + "properties": { + "withdrawal_date": { + "description": "출금일", + "type": "string", + "format": "date", + "example": "2025-01-15" + }, + "client_id": { + "description": "거래처 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "client_name": { + "description": "비회원 거래처명", + "type": "string", + "maxLength": 100, + "example": "홍길동", + "nullable": true + }, + "bank_account_id": { + "description": "출금 계좌 ID", + "type": "integer", + "example": 1, + "nullable": true + }, + "amount": { + "description": "금액", + "type": "number", + "format": "float", + "example": 500000 + }, + "payment_method": { + "description": "결제수단", + "type": "string", + "enum": [ + "cash", + "transfer", + "card", + "check" + ], + "example": "transfer" + }, + "account_code": { + "description": "계정과목", + "type": "string", + "maxLength": 20, + "example": "501", + "nullable": true + }, + "description": { + "description": "적요", + "type": "string", + "maxLength": 1000, + "example": "사무용품 구매", + "nullable": true + }, + "reference_type": { + "description": "참조 유형", + "type": "string", + "maxLength": 50, + "example": "purchase", + "nullable": true + }, + "reference_id": { + "description": "참조 ID", + "type": "integer", + "example": 1, + "nullable": true + } + }, + "type": "object" + }, + "WithdrawalSummary": { + "description": "출금 요약", + "properties": { + "total_amount": { + "description": "총 출금액", + "type": "number", + "format": "float", + "example": 3000000 + }, + "total_count": { + "description": "총 건수", + "type": "integer", + "example": 15 + }, + "by_payment_method": { + "description": "결제수단별 합계", + "properties": { + "cash": { + "properties": { + "total": { + "type": "number", + "example": 500000 + }, + "count": { + "type": "integer", + "example": 5 + } + }, + "type": "object" + }, + "transfer": { + "properties": { + "total": { + "type": "number", + "example": 2500000 + }, + "count": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "WorkOrder": { + "required": [ + "id", + "work_order_no", + "process_type", + "status" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "work_order_no": { + "type": "string", + "example": "WO202512260001" + }, + "sales_order_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "project_name": { + "type": "string", + "example": "강남빌딩 방충망", + "nullable": true + }, + "process_type": { + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ], + "example": "screen" + }, + "status": { + "type": "string", + "enum": [ + "unassigned", + "pending", + "waiting", + "in_progress", + "completed", + "shipped" + ], + "example": "pending" + }, + "assignee_id": { + "type": "integer", + "example": 10, + "nullable": true + }, + "team_id": { + "type": "integer", + "example": 5, + "nullable": true + }, + "scheduled_date": { + "type": "string", + "format": "date", + "example": "2025-12-28", + "nullable": true + }, + "started_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "completed_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "shipped_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "is_active": { + "type": "boolean", + "example": true + }, + "created_at": { + "type": "string", + "example": "2025-12-26" + }, + "updated_at": { + "type": "string", + "example": "2025-12-26" + }, + "assignee": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + }, + "team": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "WorkOrderItem": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "work_order_id": { + "type": "integer", + "example": 1 + }, + "item_id": { + "type": "integer", + "example": 100, + "nullable": true + }, + "item_name": { + "type": "string", + "example": "방충망 프레임" + }, + "specification": { + "type": "string", + "example": "W1200 x H2400", + "nullable": true + }, + "quantity": { + "type": "number", + "format": "float", + "example": 10 + }, + "unit": { + "type": "string", + "example": "EA", + "nullable": true + }, + "sort_order": { + "type": "integer", + "example": 0 + } + }, + "type": "object" + }, + "WorkOrderBendingDetail": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "work_order_id": { + "type": "integer", + "example": 1 + }, + "shaft_cutting": { + "type": "boolean", + "example": true + }, + "bearing": { + "type": "boolean", + "example": false + }, + "shaft_welding": { + "type": "boolean", + "example": false + }, + "assembly": { + "type": "boolean", + "example": false + }, + "winder_welding": { + "type": "boolean", + "example": false + }, + "frame_assembly": { + "type": "boolean", + "example": false + }, + "bundle_assembly": { + "type": "boolean", + "example": false + }, + "motor_assembly": { + "type": "boolean", + "example": false + }, + "bracket_assembly": { + "type": "boolean", + "example": false + } + }, + "type": "object" + }, + "WorkOrderIssue": { + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "work_order_id": { + "type": "integer", + "example": 1 + }, + "title": { + "type": "string", + "example": "자재 부족" + }, + "description": { + "type": "string", + "example": "방충망 프레임 재고 부족", + "nullable": true + }, + "priority": { + "type": "string", + "enum": [ + "high", + "medium", + "low" + ], + "example": "high" + }, + "status": { + "type": "string", + "enum": [ + "open", + "in_progress", + "resolved" + ], + "example": "open" + }, + "reported_by": { + "type": "integer", + "example": 10, + "nullable": true + }, + "resolved_by": { + "type": "integer", + "nullable": true + }, + "resolved_at": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "type": "object" + }, + "WorkOrderStats": { + "properties": { + "total": { + "type": "integer", + "example": 100 + }, + "unassigned": { + "type": "integer", + "example": 10 + }, + "pending": { + "type": "integer", + "example": 15 + }, + "waiting": { + "type": "integer", + "example": 5 + }, + "in_progress": { + "type": "integer", + "example": 20 + }, + "completed": { + "type": "integer", + "example": 40 + }, + "shipped": { + "type": "integer", + "example": 10 + } + }, + "type": "object" + }, + "WorkOrderPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WorkOrder" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "per_page": { + "type": "integer" + }, + "total": { + "type": "integer" + } + }, + "type": "object" + }, + "WorkOrderCreateRequest": { + "required": [ + "process_type" + ], + "properties": { + "sales_order_id": { + "type": "integer", + "nullable": true + }, + "project_name": { + "type": "string", + "maxLength": 200, + "nullable": true + }, + "process_type": { + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ] + }, + "assignee_id": { + "type": "integer", + "nullable": true + }, + "team_id": { + "type": "integer", + "nullable": true + }, + "scheduled_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "properties": { + "item_id": { + "type": "integer", + "nullable": true + }, + "item_name": { + "type": "string" + }, + "specification": { + "type": "string", + "nullable": true + }, + "quantity": { + "type": "number", + "nullable": true + }, + "unit": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + }, + "bending_detail": { + "$ref": "#/components/schemas/WorkOrderBendingDetail" + } + }, + "type": "object" + }, + "WorkOrderUpdateRequest": { + "properties": { + "sales_order_id": { + "type": "integer", + "nullable": true + }, + "project_name": { + "type": "string", + "nullable": true + }, + "process_type": { + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ], + "nullable": true + }, + "status": { + "type": "string", + "enum": [ + "unassigned", + "pending", + "waiting", + "in_progress", + "completed", + "shipped" + ], + "nullable": true + }, + "assignee_id": { + "type": "integer", + "nullable": true + }, + "team_id": { + "type": "integer", + "nullable": true + }, + "scheduled_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "items": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true + }, + "bending_detail": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "WorkResult": { + "required": [ + "id", + "lot_no", + "work_date", + "work_order_id", + "process_type", + "product_name" + ], + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "tenant_id": { + "type": "integer", + "example": 1 + }, + "work_order_id": { + "type": "integer", + "example": 1 + }, + "work_order_item_id": { + "type": "integer", + "example": 1, + "nullable": true + }, + "lot_no": { + "type": "string", + "example": "KD-TS-250212-01-01" + }, + "work_date": { + "type": "string", + "format": "date", + "example": "2025-02-12" + }, + "process_type": { + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ], + "example": "screen" + }, + "product_name": { + "type": "string", + "example": "스크린 셔터 (프리미엄)" + }, + "specification": { + "type": "string", + "example": "8000x2800", + "nullable": true + }, + "production_qty": { + "type": "integer", + "example": 10 + }, + "good_qty": { + "type": "integer", + "example": 9 + }, + "defect_qty": { + "type": "integer", + "example": 1 + }, + "defect_rate": { + "type": "number", + "format": "float", + "example": 10 + }, + "is_inspected": { + "type": "boolean", + "example": true + }, + "is_packaged": { + "type": "boolean", + "example": false + }, + "worker_id": { + "type": "integer", + "example": 10, + "nullable": true + }, + "memo": { + "type": "string", + "nullable": true + }, + "created_at": { + "type": "string", + "example": "2025-02-12T10:00:00Z" + }, + "updated_at": { + "type": "string", + "example": "2025-02-12T10:00:00Z" + }, + "work_order": { + "properties": { + "id": { + "type": "integer" + }, + "work_order_no": { + "type": "string" + } + }, + "type": "object", + "nullable": true + }, + "worker": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "WorkResultStats": { + "properties": { + "total_production": { + "description": "총 생산수량", + "type": "integer", + "example": 100 + }, + "total_good": { + "description": "총 양품수량", + "type": "integer", + "example": 95 + }, + "total_defect": { + "description": "총 불량수량", + "type": "integer", + "example": 5 + }, + "defect_rate": { + "description": "불량률 (%)", + "type": "number", + "format": "float", + "example": 5 + } + }, + "type": "object" + }, + "WorkResultPagination": { + "properties": { + "current_page": { + "type": "integer", + "example": 1 + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WorkResult" + } + }, + "first_page_url": { + "type": "string" + }, + "from": { + "type": "integer" + }, + "last_page": { + "type": "integer" + }, + "per_page": { + "type": "integer" + }, + "total": { + "type": "integer" + } + }, + "type": "object" + }, + "WorkResultCreateRequest": { + "required": [ + "work_order_id", + "lot_no", + "work_date", + "product_name", + "production_qty", + "defect_qty" + ], + "properties": { + "work_order_id": { + "description": "작업지시 ID", + "type": "integer" + }, + "work_order_item_id": { + "description": "작업지시 품목 ID", + "type": "integer", + "nullable": true + }, + "lot_no": { + "description": "로트번호", + "type": "string", + "maxLength": 50 + }, + "work_date": { + "description": "작업일", + "type": "string", + "format": "date" + }, + "process_type": { + "description": "공정구분", + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ], + "nullable": true + }, + "product_name": { + "description": "품목명", + "type": "string", + "maxLength": 200 + }, + "specification": { + "description": "규격", + "type": "string", + "maxLength": 100, + "nullable": true + }, + "production_qty": { + "description": "생산수량", + "type": "integer", + "minimum": 0 + }, + "good_qty": { + "description": "양품수량 (미입력 시 자동계산)", + "type": "integer", + "minimum": 0, + "nullable": true + }, + "defect_qty": { + "description": "불량수량", + "type": "integer", + "minimum": 0 + }, + "is_inspected": { + "description": "검사완료 여부", + "type": "boolean", + "nullable": true + }, + "is_packaged": { + "description": "포장완료 여부", + "type": "boolean", + "nullable": true + }, + "worker_id": { + "description": "작업자 ID", + "type": "integer", + "nullable": true + }, + "memo": { + "description": "비고", + "type": "string", + "maxLength": 2000, + "nullable": true + } + }, + "type": "object" + }, + "WorkResultUpdateRequest": { + "properties": { + "work_order_id": { + "type": "integer", + "nullable": true + }, + "work_order_item_id": { + "type": "integer", + "nullable": true + }, + "lot_no": { + "type": "string", + "maxLength": 50, + "nullable": true + }, + "work_date": { + "type": "string", + "format": "date", + "nullable": true + }, + "process_type": { + "type": "string", + "enum": [ + "screen", + "slat", + "bending" + ], + "nullable": true + }, + "product_name": { + "type": "string", + "maxLength": 200, + "nullable": true + }, + "specification": { + "type": "string", + "maxLength": 100, + "nullable": true + }, + "production_qty": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "good_qty": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "defect_qty": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "is_inspected": { + "type": "boolean", + "nullable": true + }, + "is_packaged": { + "type": "boolean", + "nullable": true + }, + "worker_id": { + "type": "integer", + "nullable": true + }, + "memo": { + "type": "string", + "maxLength": 2000, + "nullable": true + } + }, + "type": "object" + }, + "WorkSetting": { + "description": "근무 설정 정보", + "properties": { + "id": { + "description": "ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "work_type": { + "description": "근무유형", + "type": "string", + "enum": [ + "fixed", + "flexible", + "custom" + ], + "example": "fixed" + }, + "standard_hours": { + "description": "주당 소정근로시간", + "type": "integer", + "example": 40 + }, + "overtime_hours": { + "description": "주당 연장근로시간", + "type": "integer", + "example": 12 + }, + "overtime_limit": { + "description": "연장근로한도", + "type": "integer", + "example": 52 + }, + "work_days": { + "description": "근무요일", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ] + }, + "start_time": { + "description": "출근시간", + "type": "string", + "format": "time", + "example": "09:00:00" + }, + "end_time": { + "description": "퇴근시간", + "type": "string", + "format": "time", + "example": "18:00:00" + }, + "break_minutes": { + "description": "휴게시간(분)", + "type": "integer", + "example": 60 + }, + "break_start": { + "description": "휴게시작", + "type": "string", + "format": "time", + "example": "12:00:00", + "nullable": true + }, + "break_end": { + "description": "휴게종료", + "type": "string", + "format": "time", + "example": "13:00:00", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "WorkSettingUpdateRequest": { + "description": "근무 설정 수정 요청", + "properties": { + "work_type": { + "description": "근무유형", + "type": "string", + "enum": [ + "fixed", + "flexible", + "custom" + ], + "example": "fixed" + }, + "standard_hours": { + "description": "주당 소정근로시간", + "type": "integer", + "maximum": 168, + "minimum": 1, + "example": 40 + }, + "overtime_hours": { + "description": "주당 연장근로시간", + "type": "integer", + "maximum": 52, + "minimum": 0, + "example": 12 + }, + "overtime_limit": { + "description": "연장근로한도", + "type": "integer", + "maximum": 100, + "minimum": 0, + "example": 52 + }, + "work_days": { + "description": "근무요일", + "type": "array", + "items": { + "type": "string", + "enum": [ + "mon", + "tue", + "wed", + "thu", + "fri", + "sat", + "sun" + ] + } + }, + "start_time": { + "description": "출근시간", + "type": "string", + "format": "time", + "example": "09:00:00" + }, + "end_time": { + "description": "퇴근시간", + "type": "string", + "format": "time", + "example": "18:00:00" + }, + "break_minutes": { + "description": "휴게시간(분)", + "type": "integer", + "maximum": 180, + "minimum": 0, + "example": 60 + }, + "break_start": { + "description": "휴게시작", + "type": "string", + "format": "time", + "example": "12:00:00" + }, + "break_end": { + "description": "휴게종료", + "type": "string", + "format": "time", + "example": "13:00:00" + } + }, + "type": "object" + }, + "AttendanceSetting": { + "description": "출퇴근 설정 정보", + "properties": { + "id": { + "description": "ID", + "type": "integer", + "example": 1 + }, + "tenant_id": { + "description": "테넌트 ID", + "type": "integer", + "example": 1 + }, + "use_gps": { + "description": "GPS 출퇴근 사용 여부", + "type": "boolean", + "example": true + }, + "allowed_radius": { + "description": "허용 반경(m)", + "type": "integer", + "example": 100 + }, + "hq_address": { + "description": "본사 주소", + "type": "string", + "example": "서울시 강남구 테헤란로 123", + "nullable": true + }, + "hq_latitude": { + "description": "본사 위도", + "type": "number", + "format": "float", + "example": 37.5012, + "nullable": true + }, + "hq_longitude": { + "description": "본사 경도", + "type": "number", + "format": "float", + "example": 127.0396, + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "AttendanceSettingUpdateRequest": { + "description": "출퇴근 설정 수정 요청", + "properties": { + "use_gps": { + "description": "GPS 출퇴근 사용 여부", + "type": "boolean", + "example": true + }, + "allowed_radius": { + "description": "허용 반경(m)", + "type": "integer", + "maximum": 10000, + "minimum": 10, + "example": 100 + }, + "hq_address": { + "description": "본사 주소", + "type": "string", + "example": "서울시 강남구 테헤란로 123" + }, + "hq_latitude": { + "description": "본사 위도", + "type": "number", + "format": "float", + "maximum": 90, + "minimum": -90, + "example": 37.5012 + }, + "hq_longitude": { + "description": "본사 경도", + "type": "number", + "format": "float", + "maximum": 180, + "minimum": -180, + "example": 127.0396 + } + }, + "type": "object" + } + }, + "parameters": { + "Page": { + "name": "page", + "in": "query", + "description": "페이지 번호(1부터)", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "example": 1 + } + }, + "Size": { + "name": "size", + "in": "query", + "description": "페이지 당 개수(기본 20)", + "required": false, + "schema": { + "type": "integer", + "maximum": 200, + "minimum": 1, + "example": 20 + } + } + }, "securitySchemes": { "ApiKeyAuth": { "type": "apiKey", @@ -758,20 +91320,436 @@ }, "tags": [ { - "name": "API Key 인증", - "description": "API Key 인증" + "name": "Account", + "description": "계정 관리 (탈퇴, 사용중지, 약관동의)" + }, + { + "name": "Admin-Users", + "description": "관리자 사용자 관리 API" + }, + { + "name": "AI Reports", + "description": "AI 리포트 관리" + }, + { + "name": "Approvals", + "description": "전자결재 문서 관리" + }, + { + "name": "Approval Forms", + "description": "결재 양식 관리" + }, + { + "name": "Approval Lines", + "description": "결재선 템플릿 관리" + }, + { + "name": "Attendances", + "description": "근태 관리 (HR)" + }, + { + "name": "Design Audit", + "description": "Design-time audit logs" + }, + { + "name": "BadDebt", + "description": "악성채권 추심관리" + }, + { + "name": "BankAccounts", + "description": "계좌 관리" + }, + { + "name": "BarobillSettings", + "description": "바로빌 설정 관리" + }, + { + "name": "Bidding", + "description": "입찰관리 API" + }, + { + "name": "Bills", + "description": "어음 관리 API" + }, + { + "name": "Board", + "description": "게시판 관리" + }, + { + "name": "BOM Calculation", + "description": "BOM 계산 시스템" + }, + { + "name": "Cards", + "description": "카드 관리" + }, + { + "name": "Category", + "description": "카테고리 관리" + }, + { + "name": "Classification", + "description": "분류 관리 (평면 구조 / 코드 테이블)" + }, + { + "name": "Client", + "description": "거래처 관리" + }, + { + "name": "ClientGroup", + "description": "고객 그룹 관리" + }, + { + "name": "Settings - Common Codes", + "description": "공통 코드 관리 API" + }, + { + "name": "Companies", + "description": "회사 관리" + }, + { + "name": "Contract", + "description": "시공관리 - 계약관리" + }, + { + "name": "Dashboard", + "description": "대시보드" + }, + { + "name": "Deposits", + "description": "입금 관리" + }, + { + "name": "Design BOM", + "description": "Design-time BOM template operations" + }, + { + "name": "Documents", + "description": "문서 관리" + }, + { + "name": "Employees", + "description": "사원 관리 (HR)" + }, + { + "name": "ItemMaster-Relationships", + "description": "품목기준관리 - 엔티티 관계 API" + }, + { + "name": "Estimate", + "description": "견적 관리 API" + }, + { + "name": "ExpectedExpense", + "description": "미지급비용(지출예상내역) 관리" + }, + { + "name": "Tenant.Option Groups", + "description": "테넌트 관리형 옵션 그룹" + }, + { + "name": "Tenant.Option Values", + "description": "옵션 그룹의 항목(값) 관리" + }, + { + "name": "Tenant.Profiles", + "description": "테넌트별 회원 프로필 조회/수정" + }, + { + "name": "Files", + "description": "파일 저장소 관리" + }, + { + "name": "Folder", + "description": "폴더 관리" + }, + { + "name": "ItemMaster", + "description": "품목기준관리 API" + }, + { + "name": "Items", + "description": "품목 관리 (Product + Material CRUD)" + }, + { + "name": "Items BOM", + "description": "품목 BOM 관리" + }, + { + "name": "Items Files", + "description": "품목 파일 관리 API - group_id 기반, field_key 동적 지원" + }, + { + "name": "Leaves", + "description": "휴가 관리 (HR)" + }, + { + "name": "Loans", + "description": "가지급금 관리" + }, + { + "name": "NotificationSetting", + "description": "알림 설정 관리" + }, + { + "name": "Order", + "description": "수주관리 API" + }, + { + "name": "Payments", + "description": "결제 관리" + }, + { + "name": "Payrolls", + "description": "급여 관리" + }, + { + "name": "Plans", + "description": "요금제 관리" + }, + { + "name": "Popup", + "description": "팝업관리" + }, + { + "name": "Position", + "description": "직급/직책 통합 관리" + }, + { + "name": "Post", + "description": "게시글 관리" + }, + { + "name": "Pricing", + "description": "단가 관리" + }, + { + "name": "Products", + "description": "제품/부품/서브어셈블리 CRUD" + }, + { + "name": "Products-BOM", + "description": "제품 BOM (제품/자재 혼합) 관리" + }, + { + "name": "Purchases", + "description": "매입 관리" + }, + { + "name": "Quote", + "description": "견적 관리" + }, + { + "name": "Receivings", + "description": "입고 관리" + }, + { + "name": "Reports", + "description": "보고서 관리" }, { "name": "Auth", - "description": "Auth" + "description": "로그인/로그아웃 및 인증 관련 API\n *\n * **인증 흐름 (Authentication Flow)**\n * 1. 모든 API 요청은 반드시 X-API-KEY 헤더가 필요합니다 (API Key 인증)\n * 2. 사용자 인증이 필요한 API는 추가로 Bearer 토큰이 필요합니다 (JWT 인증)\n *\n * **API Key 사용 예시:**\n * ```\n * X-API-KEY: your-api-key-here\n * ```\n *\n * **Bearer Token 사용 예시:**\n * ```\n * Authorization: Bearer 1|abc123xyz456\n * ```\n *\n * **IP 기반 접근:**\n * - API Key가 없는 경우, IP 주소로 접근 제어가 가능합니다\n * - 단, 운영 환경에서는 반드시 API Key 사용을 권장합니다" }, { - "name": "Member", - "description": "Member" + "name": "User", + "description": "사용자 자기 계정 관련 API" }, { - "name": "Product", - "description": "Product" + "name": "Sales", + "description": "매출 관리" + }, + { + "name": "Shipments", + "description": "출하 관리" + }, + { + "name": "Sites", + "description": "현장 관리" + }, + { + "name": "Stats", + "description": "통계 (sam_stat DB 기반)" + }, + { + "name": "Stocks", + "description": "재고 현황" + }, + { + "name": "Subscriptions", + "description": "구독 관리" + }, + { + "name": "SystemBoard", + "description": "시스템 게시판 관리 (is_system=true, tenant_id=null)" + }, + { + "name": "TaxInvoices", + "description": "세금계산서 관리" + }, + { + "name": "Settings - Fields", + "description": "테넌트 필드 설정 관리 API" + }, + { + "name": "TenantSettings", + "description": "테넌트 설정 관리 API" + }, + { + "name": "TenantStatField", + "description": "통계 필드 메타데이터 관리" + }, + { + "name": "TodayIssue", + "description": "CEO 대시보드 - 오늘의 이슈 리스트 API" + }, + { + "name": "UserInvitation", + "description": "사용자 초대 관리" + }, + { + "name": "Withdrawals", + "description": "출금 관리" + }, + { + "name": "WorkOrder", + "description": "작업지시 관리" + }, + { + "name": "WorkResult", + "description": "작업실적 관리" + }, + { + "name": "WorkSettings", + "description": "근무/출퇴근 설정" + }, + { + "name": "Admin FCM", + "description": "Admin FCM" + }, + { + "name": "Admin.GlobalMenu", + "description": "Admin.GlobalMenu" + }, + { + "name": "BankTransaction", + "description": "BankTransaction" + }, + { + "name": "Calendar", + "description": "Calendar" + }, + { + "name": "CardTransaction", + "description": "CardTransaction" + }, + { + "name": "Category-Fields", + "description": "Category-Fields" + }, + { + "name": "Category-Templates", + "description": "Category-Templates" + }, + { + "name": "Category-Logs", + "description": "Category-Logs" + }, + { + "name": "ComprehensiveAnalysis", + "description": "ComprehensiveAnalysis" + }, + { + "name": "DailyReport", + "description": "DailyReport" + }, + { + "name": "Department", + "description": "Department" + }, + { + "name": "Model", + "description": "Model" + }, + { + "name": "ModelVersion", + "description": "ModelVersion" + }, + { + "name": "BomTemplate", + "description": "BomTemplate" + }, + { + "name": "Entertainment", + "description": "Entertainment" + }, + { + "name": "Internal", + "description": "Internal" + }, + { + "name": "LeavePolicy", + "description": "LeavePolicy" + }, + { + "name": "Material", + "description": "Material" + }, + { + "name": "Menu", + "description": "Menu" + }, + { + "name": "ModelSet", + "description": "ModelSet" + }, + { + "name": "Permission", + "description": "Permission" + }, + { + "name": "Process", + "description": "Process" + }, + { + "name": "Push", + "description": "Push" + }, + { + "name": "Receivables", + "description": "Receivables" + }, + { + "name": "Role", + "description": "Role" + }, + { + "name": "RolePermission", + "description": "RolePermission" + }, + { + "name": "StatusBoard", + "description": "StatusBoard" + }, + { + "name": "Tenant", + "description": "Tenant" + }, + { + "name": "UserRole", + "description": "UserRole" + }, + { + "name": "Vat", + "description": "Vat" + }, + { + "name": "VendorLedger", + "description": "VendorLedger" + }, + { + "name": "Welfare", + "description": "Welfare" } ] } \ No newline at end of file