// config/swagger.js - Swagger/OpenAPI 설정 const swaggerJSDoc = require('swagger-jsdoc'); const swaggerDefinition = { openapi: '3.0.0', info: { title: 'Technical Korea Work Management API', version: '2.1.0', description: '보안이 강화된 생산관리 시스템 API - 작업자, 프로젝트, 일일 작업 보고서 관리', contact: { name: 'Technical Korea', email: 'admin@technicalkorea.com' }, license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' } }, servers: [ { url: 'http://localhost:20005', description: '개발 서버 (Docker)' }, { url: 'http://localhost:3005', description: '로컬 개발 서버' } ], components: { securitySchemes: { bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT', description: 'JWT 토큰을 사용한 인증. 로그인 후 받은 토큰을 "Bearer {token}" 형식으로 입력하세요.' } }, schemas: { // 공통 응답 스키마 SuccessResponse: { type: 'object', properties: { success: { type: 'boolean', example: true }, message: { type: 'string', example: '요청이 성공적으로 처리되었습니다.' }, data: { type: 'object', description: '응답 데이터' }, timestamp: { type: 'string', format: 'date-time', example: '2024-01-01T00:00:00.000Z' } } }, ErrorResponse: { type: 'object', properties: { success: { type: 'boolean', example: false }, error: { type: 'string', example: '오류 메시지' }, timestamp: { type: 'string', format: 'date-time', example: '2024-01-01T00:00:00.000Z' } } }, PaginatedResponse: { type: 'object', properties: { success: { type: 'boolean', example: true }, message: { type: 'string', example: '데이터 조회 성공' }, data: { type: 'array', items: { type: 'object' } }, meta: { type: 'object', properties: { pagination: { type: 'object', properties: { currentPage: { type: 'integer', example: 1 }, totalPages: { type: 'integer', example: 10 }, totalCount: { type: 'integer', example: 100 }, limit: { type: 'integer', example: 10 }, hasNextPage: { type: 'boolean', example: true }, hasPrevPage: { type: 'boolean', example: false } } } } }, timestamp: { type: 'string', format: 'date-time' } } }, // 사용자 관련 스키마 User: { type: 'object', properties: { user_id: { type: 'integer', example: 1, description: '사용자 ID' }, username: { type: 'string', example: 'admin', description: '사용자명' }, name: { type: 'string', example: '관리자', description: '실명' }, email: { type: 'string', format: 'email', example: 'admin@technicalkorea.com', description: '이메일 주소' }, role: { type: 'string', example: 'admin', description: '역할' }, access_level: { type: 'string', enum: ['user', 'admin', 'system'], example: 'admin', description: '접근 권한 레벨' }, worker_id: { type: 'integer', example: 1, description: '연결된 작업자 ID' }, is_active: { type: 'boolean', example: true, description: '활성 상태' }, last_login_at: { type: 'string', format: 'date-time', description: '마지막 로그인 시간' }, created_at: { type: 'string', format: 'date-time', description: '생성 시간' }, updated_at: { type: 'string', format: 'date-time', description: '수정 시간' } } }, // 작업자 관련 스키마 Worker: { type: 'object', properties: { worker_id: { type: 'integer', example: 1, description: '작업자 ID' }, worker_name: { type: 'string', example: '김철수', description: '작업자 이름' }, position: { type: 'string', example: '용접공', description: '직책' }, department: { type: 'string', example: '생산부', description: '부서' }, phone: { type: 'string', example: '010-1234-5678', description: '전화번호' }, email: { type: 'string', format: 'email', example: 'worker@technicalkorea.com', description: '이메일' }, hire_date: { type: 'string', format: 'date', example: '2024-01-01', description: '입사일' }, is_active: { type: 'boolean', example: true, description: '활성 상태' }, created_at: { type: 'string', format: 'date-time', description: '생성 시간' }, updated_at: { type: 'string', format: 'date-time', description: '수정 시간' } } }, // 프로젝트 관련 스키마 Project: { type: 'object', properties: { project_id: { type: 'integer', example: 1, description: '프로젝트 ID' }, project_name: { type: 'string', example: '신규 플랜트 건설', description: '프로젝트 이름' }, description: { type: 'string', example: '대형 화학 플랜트 건설 프로젝트', description: '프로젝트 설명' }, start_date: { type: 'string', format: 'date', example: '2024-01-01', description: '시작일' }, end_date: { type: 'string', format: 'date', example: '2024-12-31', description: '종료일' }, status: { type: 'string', example: 'active', description: '프로젝트 상태' }, created_at: { type: 'string', format: 'date-time', description: '생성 시간' }, updated_at: { type: 'string', format: 'date-time', description: '수정 시간' } } }, // 작업 관련 스키마 Task: { type: 'object', properties: { task_id: { type: 'integer', example: 1, description: '작업 ID' }, task_name: { type: 'string', example: '용접 작업', description: '작업 이름' }, description: { type: 'string', example: '파이프 용접 작업', description: '작업 설명' }, category: { type: 'string', example: '용접', description: '작업 카테고리' }, is_active: { type: 'boolean', example: true, description: '활성 상태' }, created_at: { type: 'string', format: 'date-time', description: '생성 시간' }, updated_at: { type: 'string', format: 'date-time', description: '수정 시간' } } }, // 일일 작업 보고서 관련 스키마 DailyWorkReport: { type: 'object', properties: { id: { type: 'integer', example: 1, description: '보고서 ID' }, report_date: { type: 'string', format: 'date', example: '2024-01-01', description: '작업 날짜' }, worker_id: { type: 'integer', example: 1, description: '작업자 ID' }, project_id: { type: 'integer', example: 1, description: '프로젝트 ID' }, work_type_id: { type: 'integer', example: 1, description: '작업 유형 ID' }, work_status_id: { type: 'integer', example: 1, description: '작업 상태 ID (1:정규, 2:에러)' }, error_type_id: { type: 'integer', example: null, description: '에러 유형 ID (에러일 때만)' }, work_hours: { type: 'number', format: 'decimal', example: 8.5, description: '작업 시간' }, created_by: { type: 'integer', example: 1, description: '작성자 user_id' }, created_at: { type: 'string', format: 'date-time', description: '생성 시간' }, updated_at: { type: 'string', format: 'date-time', description: '수정 시간' }, // 조인된 데이터 worker_name: { type: 'string', example: '김철수', description: '작업자 이름' }, project_name: { type: 'string', example: '신규 플랜트 건설', description: '프로젝트 이름' }, work_type_name: { type: 'string', example: '용접', description: '작업 유형 이름' }, work_status_name: { type: 'string', example: '정규', description: '작업 상태 이름' }, error_type_name: { type: 'string', example: null, description: '에러 유형 이름' } } }, // 로그인 관련 스키마 LoginRequest: { type: 'object', required: ['username', 'password'], properties: { username: { type: 'string', example: 'admin', description: '사용자명' }, password: { type: 'string', example: 'password123', description: '비밀번호' } } }, LoginResponse: { type: 'object', properties: { success: { type: 'boolean', example: true }, message: { type: 'string', example: '로그인 성공' }, data: { type: 'object', properties: { user: { $ref: '#/components/schemas/User' }, token: { type: 'string', example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', description: 'JWT 토큰' }, redirectUrl: { type: 'string', example: '/pages/dashboard/group-leader.html', description: '리다이렉트 URL' } } }, timestamp: { type: 'string', format: 'date-time' } } } } }, security: [ { bearerAuth: [] } ] }; const options = { definition: swaggerDefinition, apis: [ './routes/*.js', './controllers/*.js', './index.js' ] }; const swaggerSpec = swaggerJSDoc(options); module.exports = swaggerSpec;