Files
tk-factory-services/system1-factory/api/config/swagger.js
Hyungi Ahn 550633b89d feat: 3-System 분리 프로젝트 초기 코드 작성
TK-FB(공장관리+신고)와 M-Project(부적합관리)를 3개 독립 시스템으로
분리하기 위한 전체 코드 구조 작성.
- SSO 인증 서비스 (bcrypt + pbkdf2 이중 해시 지원)
- System 1: 공장관리 (TK-FB 기반, 신고 코드 제거)
- System 2: 신고 (TK-FB에서 workIssue 코드 추출)
- System 3: 부적합관리 (M-Project 기반)
- Gateway 포털 (path-based 라우팅)
- 통합 docker-compose.yml 및 배포 스크립트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 14:40:11 +09:00

498 lines
13 KiB
JavaScript

// 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;