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>
189 lines
4.2 KiB
JavaScript
189 lines
4.2 KiB
JavaScript
// utils/responseFormatter.js - 통합 응답 포맷터
|
|
|
|
/**
|
|
* 성공 응답 포맷터
|
|
*/
|
|
const successResponse = (data = null, message = '요청이 성공적으로 처리되었습니다.', meta = null) => {
|
|
const response = {
|
|
success: true,
|
|
message,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
if (data !== null) {
|
|
response.data = data;
|
|
}
|
|
|
|
if (meta) {
|
|
response.meta = meta;
|
|
}
|
|
|
|
return response;
|
|
};
|
|
|
|
/**
|
|
* 페이지네이션 응답 포맷터
|
|
*/
|
|
const paginatedResponse = (data, totalCount, page = 1, limit = 10, message = '데이터 조회 성공') => {
|
|
const totalPages = Math.ceil(totalCount / limit);
|
|
|
|
return successResponse(data, message, {
|
|
pagination: {
|
|
currentPage: parseInt(page),
|
|
totalPages,
|
|
totalCount: parseInt(totalCount),
|
|
limit: parseInt(limit),
|
|
hasNextPage: page < totalPages,
|
|
hasPrevPage: page > 1
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 리스트 응답 포맷터
|
|
*/
|
|
const listResponse = (items, message = '목록 조회 성공') => {
|
|
return successResponse(items, message, {
|
|
count: items.length
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 생성 응답 포맷터
|
|
*/
|
|
const createdResponse = (data, message = '데이터가 성공적으로 생성되었습니다.') => {
|
|
return successResponse(data, message);
|
|
};
|
|
|
|
/**
|
|
* 업데이트 응답 포맷터
|
|
*/
|
|
const updatedResponse = (data = null, message = '데이터가 성공적으로 업데이트되었습니다.') => {
|
|
return successResponse(data, message);
|
|
};
|
|
|
|
/**
|
|
* 삭제 응답 포맷터
|
|
*/
|
|
const deletedResponse = (message = '데이터가 성공적으로 삭제되었습니다.') => {
|
|
return successResponse(null, message);
|
|
};
|
|
|
|
/**
|
|
* 통계 응답 포맷터
|
|
*/
|
|
const statsResponse = (stats, period = null, message = '통계 조회 성공') => {
|
|
const meta = {};
|
|
if (period) {
|
|
meta.period = period;
|
|
}
|
|
meta.generatedAt = new Date().toISOString();
|
|
|
|
return successResponse(stats, message, meta);
|
|
};
|
|
|
|
/**
|
|
* 인증 응답 포맷터
|
|
*/
|
|
const authResponse = (user, token, redirectUrl = null, message = '로그인 성공') => {
|
|
const data = {
|
|
user,
|
|
token
|
|
};
|
|
|
|
if (redirectUrl) {
|
|
data.redirectUrl = redirectUrl;
|
|
}
|
|
|
|
return successResponse(data, message);
|
|
};
|
|
|
|
/**
|
|
* 파일 업로드 응답 포맷터
|
|
*/
|
|
const uploadResponse = (fileInfo, message = '파일 업로드 성공') => {
|
|
return successResponse({
|
|
filename: fileInfo.filename,
|
|
originalName: fileInfo.originalname,
|
|
size: fileInfo.size,
|
|
mimetype: fileInfo.mimetype,
|
|
path: fileInfo.path,
|
|
uploadedAt: new Date().toISOString()
|
|
}, message);
|
|
};
|
|
|
|
/**
|
|
* 헬스체크 응답 포맷터
|
|
*/
|
|
const healthResponse = (status = 'healthy', services = {}) => {
|
|
return successResponse({
|
|
status,
|
|
services,
|
|
uptime: process.uptime(),
|
|
memory: process.memoryUsage(),
|
|
version: process.version
|
|
}, `서버 상태: ${status}`);
|
|
};
|
|
|
|
/**
|
|
* Express 응답 확장 미들웨어
|
|
*/
|
|
const responseMiddleware = (req, res, next) => {
|
|
// 성공 응답 헬퍼들을 res 객체에 추가
|
|
res.success = (data, message, meta) => {
|
|
return res.json(successResponse(data, message, meta));
|
|
};
|
|
|
|
res.paginated = (data, totalCount, page, limit, message) => {
|
|
return res.json(paginatedResponse(data, totalCount, page, limit, message));
|
|
};
|
|
|
|
res.list = (items, message) => {
|
|
return res.json(listResponse(items, message));
|
|
};
|
|
|
|
res.created = (data, message) => {
|
|
return res.status(201).json(createdResponse(data, message));
|
|
};
|
|
|
|
res.updated = (data, message) => {
|
|
return res.json(updatedResponse(data, message));
|
|
};
|
|
|
|
res.deleted = (message) => {
|
|
return res.json(deletedResponse(message));
|
|
};
|
|
|
|
res.stats = (stats, period, message) => {
|
|
return res.json(statsResponse(stats, period, message));
|
|
};
|
|
|
|
res.auth = (user, token, redirectUrl, message) => {
|
|
return res.json(authResponse(user, token, redirectUrl, message));
|
|
};
|
|
|
|
res.upload = (fileInfo, message) => {
|
|
return res.json(uploadResponse(fileInfo, message));
|
|
};
|
|
|
|
res.health = (status, services) => {
|
|
return res.json(healthResponse(status, services));
|
|
};
|
|
|
|
next();
|
|
};
|
|
|
|
module.exports = {
|
|
successResponse,
|
|
paginatedResponse,
|
|
listResponse,
|
|
createdResponse,
|
|
updatedResponse,
|
|
deletedResponse,
|
|
statsResponse,
|
|
authResponse,
|
|
uploadResponse,
|
|
healthResponse,
|
|
responseMiddleware
|
|
};
|