feat: 초기 프로젝트 설정 및 룰.md 파일 추가
This commit is contained in:
210
api.hyungi.net/routes/auth.js
Normal file
210
api.hyungi.net/routes/auth.js
Normal file
@@ -0,0 +1,210 @@
|
||||
// routes/auth.js
|
||||
const express = require('express');
|
||||
const bcrypt = require('bcrypt');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const { verifyToken } = require('../middlewares/authMiddleware');
|
||||
const { requireAccess } = require('../utils/access');
|
||||
const router = express.Router();
|
||||
|
||||
// 임시 사용자 데이터
|
||||
let users = [
|
||||
{
|
||||
user_id: 1,
|
||||
username: 'admin',
|
||||
password: '$2b$10$example',
|
||||
name: '관리자',
|
||||
access_level: 'admin',
|
||||
worker_id: null,
|
||||
created_at: new Date()
|
||||
},
|
||||
{
|
||||
user_id: 2,
|
||||
username: 'group_leader1',
|
||||
password: '$2b$10$example',
|
||||
name: '김그룹장',
|
||||
access_level: 'group_leader',
|
||||
worker_id: 1,
|
||||
created_at: new Date()
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* 로그인
|
||||
*/
|
||||
router.post('/login', async (req, res) => {
|
||||
try {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ error: '사용자명과 비밀번호를 입력해주세요.' });
|
||||
}
|
||||
|
||||
const user = users.find(u => u.username === username);
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: '사용자를 찾을 수 없습니다.' });
|
||||
}
|
||||
|
||||
// 비밀번호 확인 (실제로는 bcrypt.compare 사용)
|
||||
const isValid = password === 'password'; // 임시
|
||||
if (!isValid) {
|
||||
return res.status(401).json({ error: '비밀번호가 올바르지 않습니다.' });
|
||||
}
|
||||
|
||||
// JWT 토큰 생성
|
||||
const token = jwt.sign(
|
||||
{
|
||||
user_id: user.user_id,
|
||||
username: user.username,
|
||||
access_level: user.access_level,
|
||||
worker_id: user.worker_id
|
||||
},
|
||||
process.env.JWT_SECRET || 'your-secret-key',
|
||||
{ expiresIn: '24h' }
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
token,
|
||||
user: {
|
||||
user_id: user.user_id,
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
access_level: user.access_level,
|
||||
worker_id: user.worker_id
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
res.status(500).json({ error: '서버 오류가 발생했습니다.' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 현재 사용자 정보 조회
|
||||
*/
|
||||
router.get('/me', verifyToken, (req, res) => {
|
||||
try {
|
||||
const userId = req.user.user_id;
|
||||
const user = users.find(u => u.user_id === userId);
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: '사용자를 찾을 수 없습니다.' });
|
||||
}
|
||||
|
||||
res.json({
|
||||
user_id: user.user_id,
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
access_level: user.access_level,
|
||||
worker_id: user.worker_id
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Get current user error:', error);
|
||||
res.status(500).json({ error: '서버 오류가 발생했습니다.' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 사용자 등록 (관리자만)
|
||||
*/
|
||||
router.post('/register', verifyToken, requireAccess('admin'), async (req, res) => {
|
||||
try {
|
||||
const { username, password, name, access_level, worker_id } = req.body;
|
||||
|
||||
if (!username || !password || !name || !access_level) {
|
||||
return res.status(400).json({ error: '필수 항목을 모두 입력해주세요.' });
|
||||
}
|
||||
|
||||
// 사용자명 중복 체크
|
||||
const existingUser = users.find(u => u.username === username);
|
||||
if (existingUser) {
|
||||
return res.status(409).json({ error: '이미 존재하는 사용자명입니다.' });
|
||||
}
|
||||
|
||||
// 비밀번호 해시
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
const newUser = {
|
||||
user_id: users.length + 1,
|
||||
username,
|
||||
password: hashedPassword,
|
||||
name,
|
||||
access_level,
|
||||
worker_id: worker_id || null,
|
||||
created_at: new Date()
|
||||
};
|
||||
|
||||
users.push(newUser);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '사용자가 성공적으로 등록되었습니다.',
|
||||
user: {
|
||||
user_id: newUser.user_id,
|
||||
username: newUser.username,
|
||||
name: newUser.name,
|
||||
access_level: newUser.access_level,
|
||||
worker_id: newUser.worker_id
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Register error:', error);
|
||||
res.status(500).json({ error: '서버 오류가 발생했습니다.' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 사용자 목록 조회 (관리자만)
|
||||
*/
|
||||
router.get('/users', verifyToken, requireAccess('admin'), (req, res) => {
|
||||
try {
|
||||
const userList = users.map(user => ({
|
||||
user_id: user.user_id,
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
access_level: user.access_level,
|
||||
worker_id: user.worker_id,
|
||||
created_at: user.created_at
|
||||
}));
|
||||
|
||||
res.json(userList);
|
||||
} catch (error) {
|
||||
console.error('Get users error:', error);
|
||||
res.status(500).json({ error: '서버 오류가 발생했습니다.' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 사용자 삭제 (관리자만)
|
||||
*/
|
||||
router.delete('/users/:id', verifyToken, requireAccess('admin'), (req, res) => {
|
||||
try {
|
||||
const userId = parseInt(req.params.id);
|
||||
|
||||
// 자기 자신 삭제 방지
|
||||
if (userId === req.user.user_id) {
|
||||
return res.status(400).json({ error: '자기 자신은 삭제할 수 없습니다.' });
|
||||
}
|
||||
|
||||
const userIndex = users.findIndex(u => u.user_id === userId);
|
||||
if (userIndex === -1) {
|
||||
return res.status(404).json({ error: '사용자를 찾을 수 없습니다.' });
|
||||
}
|
||||
|
||||
users.splice(userIndex, 1);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '사용자가 성공적으로 삭제되었습니다.'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Delete user error:', error);
|
||||
res.status(500).json({ error: '서버 오류가 발생했습니다.' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
1041
api.hyungi.net/routes/authRoutes.js
Normal file
1041
api.hyungi.net/routes/authRoutes.js
Normal file
File diff suppressed because it is too large
Load Diff
21
api.hyungi.net/routes/cuttingPlanRoutes.js
Normal file
21
api.hyungi.net/routes/cuttingPlanRoutes.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// routes/cuttingPlanRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const cuttingPlanController = require('../controllers/cuttingPlanController');
|
||||
|
||||
// CREATE
|
||||
router.post('/', cuttingPlanController.createCuttingPlan);
|
||||
|
||||
// READ ALL
|
||||
router.get('/', cuttingPlanController.getAllCuttingPlans);
|
||||
|
||||
// READ ONE
|
||||
router.get('/:cutting_plan_id', cuttingPlanController.getCuttingPlanById);
|
||||
|
||||
// UPDATE
|
||||
router.put('/:cutting_plan_id', cuttingPlanController.updateCuttingPlan);
|
||||
|
||||
// DELETE
|
||||
router.delete('/:cutting_plan_id', cuttingPlanController.removeCuttingPlan);
|
||||
|
||||
module.exports = router;
|
||||
20
api.hyungi.net/routes/dailyIssueReportRoutes.js
Normal file
20
api.hyungi.net/routes/dailyIssueReportRoutes.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// routes/dailyIssueReportRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
const {
|
||||
createDailyIssueReport,
|
||||
getDailyIssuesByDate,
|
||||
removeDailyIssue
|
||||
} = require('../controllers/dailyIssueReportController');
|
||||
|
||||
// 1. 등록 (단일 또는 다중)
|
||||
router.post('/', createDailyIssueReport);
|
||||
|
||||
// 2. 날짜별 조회 (?date=YYYY-MM-DD 형식)
|
||||
router.get('/', getDailyIssuesByDate);
|
||||
|
||||
// 3. 삭제
|
||||
router.delete('/:id', removeDailyIssue);
|
||||
|
||||
module.exports = router;
|
||||
72
api.hyungi.net/routes/dailyWorkReportRoutes.js
Normal file
72
api.hyungi.net/routes/dailyWorkReportRoutes.js
Normal file
@@ -0,0 +1,72 @@
|
||||
// routes/dailyWorkReportRoutes.js - 누적입력 방식 + 모든 기존 기능 포함
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const dailyWorkReportController = require('../controllers/dailyWorkReportController');
|
||||
|
||||
// 📋 마스터 데이터 조회 라우트들 (모든 인증된 사용자)
|
||||
router.get('/work-types', dailyWorkReportController.getWorkTypes);
|
||||
router.get('/work-status-types', dailyWorkReportController.getWorkStatusTypes);
|
||||
router.get('/error-types', dailyWorkReportController.getErrorTypes);
|
||||
|
||||
// 🔄 누적 관련 새로운 라우트들 (누적입력 시스템 전용)
|
||||
router.get('/accumulated', dailyWorkReportController.getAccumulatedReports); // ?date=2024-06-16&worker_id=1
|
||||
router.get('/contributors', dailyWorkReportController.getContributorsSummary); // ?date=2024-06-16&worker_id=1
|
||||
router.get('/my-data', dailyWorkReportController.getMyAccumulatedData); // ?date=2024-06-16&worker_id=1
|
||||
|
||||
// ✅ check-overwrite 엔드포인트 추가 (누락된 엔드포인트)
|
||||
router.get('/check-overwrite', (req, res) => {
|
||||
const { date, worker_id } = req.query;
|
||||
|
||||
if (!date || !worker_id) {
|
||||
return res.status(400).json({
|
||||
error: 'date와 worker_id가 필요합니다.',
|
||||
example: 'date=2025-06-16&worker_id=1'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`🔍 덮어쓰기 권한 확인: 날짜=${date}, 작업자=${worker_id} (누적입력모드)`);
|
||||
|
||||
// 누적입력 시스템에서는 항상 덮어쓰기 가능 (실제로는 누적만 함)
|
||||
res.json({
|
||||
canOverwrite: true,
|
||||
reason: 'accumulate_mode',
|
||||
message: '누적입력 모드에서는 항상 추가 가능합니다.',
|
||||
date,
|
||||
worker_id,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
router.delete('/my-entry/:id', dailyWorkReportController.removeMyEntry); // 개별 항목 삭제 (본인 것만)
|
||||
|
||||
// 📅 월간 요약 (반드시 다른 라우트보다 먼저 정의)
|
||||
router.get('/summary/monthly', dailyWorkReportController.getMonthlySummary);
|
||||
|
||||
// 📊 일일 근무 요약 조회
|
||||
router.get('/summary', dailyWorkReportController.getDailySummary);
|
||||
|
||||
// 🔍 검색 (페이지네이션 포함)
|
||||
router.get('/search', dailyWorkReportController.searchWorkReports);
|
||||
|
||||
// 📈 통계
|
||||
router.get('/stats', dailyWorkReportController.getWorkReportStats);
|
||||
|
||||
// 📝 일일 작업보고서 생성 (누적 방식 - 덮어쓰기 없음!)
|
||||
router.post('/', dailyWorkReportController.createDailyWorkReport);
|
||||
|
||||
// 📊 일일 작업보고서 조회 (날짜별 - 경로 파라미터)
|
||||
router.get('/date/:date', dailyWorkReportController.getDailyWorkReportsByDate);
|
||||
|
||||
// 📊 일일 작업보고서 조회 (쿼리 파라미터 기반 - 작성자별 필터링)
|
||||
router.get('/', dailyWorkReportController.getDailyWorkReports);
|
||||
|
||||
// ✏️ 작업보고서 수정
|
||||
router.put('/:id', dailyWorkReportController.updateWorkReport);
|
||||
|
||||
// 🗑️ 작업자의 특정 날짜 전체 삭제
|
||||
router.delete('/date/:date/worker/:worker_id', dailyWorkReportController.removeDailyWorkReportByDateAndWorker);
|
||||
|
||||
// 🗑️ 특정 작업보고서 삭제 (항상 가장 마지막에 정의)
|
||||
router.delete('/:id', dailyWorkReportController.removeDailyWorkReport);
|
||||
|
||||
module.exports = router;
|
||||
21
api.hyungi.net/routes/equipmentListRoutes.js
Normal file
21
api.hyungi.net/routes/equipmentListRoutes.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// routes/equipmentListRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const equipmentListController = require('../controllers/equipmentListController');
|
||||
|
||||
// CREATE
|
||||
router.post('/', equipmentListController.createEquipment);
|
||||
|
||||
// READ ALL
|
||||
router.get('/', equipmentListController.getAllEquipment);
|
||||
|
||||
// READ ONE
|
||||
router.get('/:equipment_id', equipmentListController.getEquipmentById);
|
||||
|
||||
// UPDATE
|
||||
router.put('/:equipment_id', equipmentListController.updateEquipment);
|
||||
|
||||
// DELETE
|
||||
router.delete('/:equipment_id', equipmentListController.removeEquipment);
|
||||
|
||||
module.exports = router;
|
||||
42
api.hyungi.net/routes/factoryInfoRoutes.js
Normal file
42
api.hyungi.net/routes/factoryInfoRoutes.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const multer = require('multer');
|
||||
const path = require('path');
|
||||
|
||||
const factoryInfoController = require('../controllers/factoryInfoController');
|
||||
const { verifyToken } = require('../middlewares/authMiddleware'); // ← 수정
|
||||
const { requireAccess } = require('../middlewares/accessMiddleware'); // ← 수정
|
||||
|
||||
// 📦 파일 저장 설정
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, 'public/uploads/');
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueName = `map_image-${Date.now()}${path.extname(file.originalname)}`;
|
||||
cb(null, uniqueName);
|
||||
}
|
||||
});
|
||||
const upload = multer({ storage });
|
||||
|
||||
// CREATE
|
||||
router.post(
|
||||
'/',
|
||||
verifyToken, // ← 수정
|
||||
upload.single('map_image'),
|
||||
factoryInfoController.createFactoryInfo
|
||||
);
|
||||
|
||||
// READ ALL
|
||||
router.get('/', verifyToken, factoryInfoController.getAllFactoryInfo); // ← 수정
|
||||
|
||||
// READ ONE
|
||||
router.get('/:factory_id', verifyToken, factoryInfoController.getFactoryInfoById); // ← 수정
|
||||
|
||||
// UPDATE
|
||||
router.put('/:factory_id', verifyToken, factoryInfoController.updateFactoryInfo); // ← 수정
|
||||
|
||||
// DELETE
|
||||
router.delete('/:factory_id', verifyToken, factoryInfoController.removeFactoryInfo); // ← 수정
|
||||
|
||||
module.exports = router;
|
||||
28
api.hyungi.net/routes/healthRoutes.js
Normal file
28
api.hyungi.net/routes/healthRoutes.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// routes/healthRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
// 헬스체크 엔드포인트
|
||||
router.get('/', (req, res) => {
|
||||
res.json({
|
||||
status: 'healthy',
|
||||
service: 'Technical Korea API',
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime()
|
||||
});
|
||||
});
|
||||
|
||||
// 상세 헬스체크 (옵션)
|
||||
router.get('/detail', (req, res) => {
|
||||
res.json({
|
||||
status: 'healthy',
|
||||
service: 'Technical Korea API',
|
||||
version: '2.1.0',
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime(),
|
||||
memory: process.memoryUsage(),
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
10
api.hyungi.net/routes/issueTypeRoutes.js
Normal file
10
api.hyungi.net/routes/issueTypeRoutes.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const issueTypeController = require('../controllers/issueTypeController');
|
||||
|
||||
router.post('/', issueTypeController.createIssueType);
|
||||
router.get('/', issueTypeController.getAllIssueTypes);
|
||||
router.put('/:id', issueTypeController.updateIssueType);
|
||||
router.delete('/:id', issueTypeController.removeIssueType);
|
||||
|
||||
module.exports = router;
|
||||
8
api.hyungi.net/routes/pingRoutes.js
Normal file
8
api.hyungi.net/routes/pingRoutes.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// routes/pingRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const pingController = require('../controllers/pingController');
|
||||
|
||||
router.get('/', pingController.ping);
|
||||
|
||||
module.exports = router;
|
||||
55
api.hyungi.net/routes/pipeSpecRoutes.js
Normal file
55
api.hyungi.net/routes/pipeSpecRoutes.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const pipeSpecController = require('../controllers/pipeSpecController');
|
||||
const auth = require('../middlewares/auth');
|
||||
const { requireAccess } = require('../middlewares/access');
|
||||
|
||||
// ✅ 전체 조회 (모든 사용자 가능)
|
||||
router.get(
|
||||
'/',
|
||||
auth,
|
||||
requireAccess('worker', 'group_leader', 'support_team', 'admin', 'system'),
|
||||
pipeSpecController.getAll
|
||||
);
|
||||
|
||||
// ✅ 재질 목록
|
||||
router.get(
|
||||
'/materials',
|
||||
auth,
|
||||
requireAccess('worker', 'group_leader', 'support_team', 'admin', 'system'),
|
||||
pipeSpecController.getMaterials
|
||||
);
|
||||
|
||||
// ✅ 직경 목록
|
||||
router.get(
|
||||
'/diameters',
|
||||
auth,
|
||||
requireAccess('worker', 'group_leader', 'support_team', 'admin', 'system'),
|
||||
pipeSpecController.getDiameters
|
||||
);
|
||||
|
||||
// ✅ 스케줄 목록
|
||||
router.get(
|
||||
'/schedules',
|
||||
auth,
|
||||
requireAccess('worker', 'group_leader', 'support_team', 'admin', 'system'),
|
||||
pipeSpecController.getSchedules
|
||||
);
|
||||
|
||||
// ✅ 등록 (시스템 또는 관리자만)
|
||||
router.post(
|
||||
'/',
|
||||
auth,
|
||||
requireAccess('system', 'admin'),
|
||||
pipeSpecController.create
|
||||
);
|
||||
|
||||
// ✅ 삭제 (시스템 또는 관리자만)
|
||||
router.delete(
|
||||
'/:spec_id',
|
||||
auth,
|
||||
requireAccess('system', 'admin'),
|
||||
pipeSpecController.remove
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
21
api.hyungi.net/routes/processRoutes.js
Normal file
21
api.hyungi.net/routes/processRoutes.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// routes/processRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const processController = require('../controllers/processController');
|
||||
|
||||
// CREATE
|
||||
router.post('/', processController.createProcess);
|
||||
|
||||
// READ ALL
|
||||
router.get('/', processController.getAllProcesses);
|
||||
|
||||
// READ ONE
|
||||
router.get('/:process_id', processController.getProcessById);
|
||||
|
||||
// UPDATE
|
||||
router.put('/:process_id', processController.updateProcess);
|
||||
|
||||
// DELETE
|
||||
router.delete('/:process_id', processController.removeProcess);
|
||||
|
||||
module.exports = router;
|
||||
21
api.hyungi.net/routes/projectRoutes.js
Normal file
21
api.hyungi.net/routes/projectRoutes.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// routes/projectRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const projectController = require('../controllers/projectController');
|
||||
|
||||
// CREATE
|
||||
router.post('/', projectController.createProject);
|
||||
|
||||
// READ ALL
|
||||
router.get('/', projectController.getAllProjects);
|
||||
|
||||
// READ ONE
|
||||
router.get('/:project_id', projectController.getProjectById);
|
||||
|
||||
// UPDATE
|
||||
router.put('/:project_id', projectController.updateProject);
|
||||
|
||||
// DELETE
|
||||
router.delete('/:project_id', projectController.removeProject);
|
||||
|
||||
module.exports = router;
|
||||
21
api.hyungi.net/routes/taskRoutes.js
Normal file
21
api.hyungi.net/routes/taskRoutes.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// routes/taskRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const taskController = require('../controllers/taskController');
|
||||
|
||||
// CREATE
|
||||
router.post('/', taskController.createTask);
|
||||
|
||||
// READ ALL
|
||||
router.get('/', taskController.getAllTasks);
|
||||
|
||||
// READ ONE
|
||||
router.get('/:task_id', taskController.getTaskById);
|
||||
|
||||
// UPDATE
|
||||
router.put('/:task_id', taskController.updateTask);
|
||||
|
||||
// DELETE
|
||||
router.delete('/:task_id', taskController.removeTask);
|
||||
|
||||
module.exports = router;
|
||||
12
api.hyungi.net/routes/toolsRoute.js
Normal file
12
api.hyungi.net/routes/toolsRoute.js
Normal file
@@ -0,0 +1,12 @@
|
||||
// routes/toolsRoute.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const controller = require('../controllers/toolsController');
|
||||
|
||||
router.get('/', controller.getAll);
|
||||
router.get('/:id', controller.getById);
|
||||
router.post('/', controller.create);
|
||||
router.put('/:id', controller.update);
|
||||
router.delete('/:id', controller.delete);
|
||||
|
||||
module.exports = router;
|
||||
25
api.hyungi.net/routes/uploadBgRoutes.js
Normal file
25
api.hyungi.net/routes/uploadBgRoutes.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// ✅ routes/uploadBgRoutes.js (신규: 배경 이미지 전용 업로드 라우터)
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const multer = require('multer');
|
||||
const path = require('path');
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, path.join(__dirname, '../public/img'));
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
cb(null, 'login-bg.jpeg'); // 고정된 파일명으로 덮어쓰기
|
||||
}
|
||||
});
|
||||
|
||||
const upload = multer({ storage });
|
||||
|
||||
router.post('/upload-bg', upload.single('image'), (req, res) => {
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ success: false, message: '파일이 없습니다.' });
|
||||
}
|
||||
res.json({ success: true, path: '/img/login-bg.jpeg' });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
10
api.hyungi.net/routes/uploadRoutes.js
Normal file
10
api.hyungi.net/routes/uploadRoutes.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// ✅ routes/uploadRoutes.js (기존 업로드 라우터)
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const uploadController = require('../controllers/uploadController');
|
||||
|
||||
// 기존 업로드 등록/조회
|
||||
router.post('/', uploadController.createUpload);
|
||||
router.get('/', uploadController.getUploads);
|
||||
|
||||
module.exports = router;
|
||||
74
api.hyungi.net/routes/workAnalysis.js
Normal file
74
api.hyungi.net/routes/workAnalysis.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// routes/workAnalysis.js
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const workAnalysisController = require('../controllers/workAnalysisController');
|
||||
|
||||
// 🔒 분석 기능은 admin 또는 system 권한만 접근 가능
|
||||
const requireAnalysisAccess = (req, res, next) => {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({ error: '인증이 필요합니다.' });
|
||||
}
|
||||
|
||||
const allowedLevels = ['admin', 'system'];
|
||||
if (!allowedLevels.includes(req.user.access_level)) {
|
||||
return res.status(403).json({
|
||||
error: '분석 기능 접근 권한이 없습니다. 관리자 권한이 필요합니다.',
|
||||
required: 'admin 또는 system',
|
||||
current: req.user.access_level
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`🔓 분석 기능 접근 허용: ${req.user.username} (${req.user.access_level})`);
|
||||
next();
|
||||
};
|
||||
|
||||
// 임시로 권한 체크 건너뛰기 (테스트용)
|
||||
const skipAuth = (req, res, next) => {
|
||||
console.log('⚠️ 임시로 권한 체크 건너뛰기');
|
||||
next();
|
||||
};
|
||||
|
||||
// 기본 통계 조회 - 임시로 권한 체크 비활성화
|
||||
router.get('/stats', skipAuth, workAnalysisController.getStats);
|
||||
|
||||
// 일별 작업시간 추이 - 임시로 권한 체크 비활성화
|
||||
router.get('/daily-trend', skipAuth, workAnalysisController.getDailyTrend);
|
||||
|
||||
// 작업자별 통계 - 임시로 권한 체크 비활성화
|
||||
router.get('/worker-stats', skipAuth, workAnalysisController.getWorkerStats);
|
||||
|
||||
// 프로젝트별 통계 - 임시로 권한 체크 비활성화
|
||||
router.get('/project-stats', skipAuth, workAnalysisController.getProjectStats);
|
||||
|
||||
// 작업유형별 통계 - 임시로 권한 체크 비활성화
|
||||
router.get('/worktype-stats', skipAuth, workAnalysisController.getWorkTypeStats);
|
||||
|
||||
// 최근 작업 현황 - 임시로 권한 체크 비활성화
|
||||
router.get('/recent-work', skipAuth, workAnalysisController.getRecentWork);
|
||||
|
||||
// 요일별 패턴 분석
|
||||
router.get('/weekday-pattern', requireAnalysisAccess, workAnalysisController.getWeekdayPattern);
|
||||
|
||||
// 에러 분석
|
||||
router.get('/error-analysis', requireAnalysisAccess, workAnalysisController.getErrorAnalysis);
|
||||
|
||||
// 월별 비교 분석
|
||||
router.get('/monthly-comparison', requireAnalysisAccess, workAnalysisController.getMonthlyComparison);
|
||||
|
||||
// 작업자별 전문분야 분석
|
||||
router.get('/worker-specialization', requireAnalysisAccess, workAnalysisController.getWorkerSpecialization);
|
||||
|
||||
// 대시보드용 종합 데이터 (한 번에 여러 데이터 조회)
|
||||
router.get('/dashboard', requireAnalysisAccess, workAnalysisController.getDashboardData);
|
||||
|
||||
// 헬스체크 - 인증 없이 접근 가능
|
||||
router.get('/health', (req, res) => {
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Work Analysis API is running',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
61
api.hyungi.net/routes/workAnalysisRoutes.js
Normal file
61
api.hyungi.net/routes/workAnalysisRoutes.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// routes/workAnalysisRoutes.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const workAnalysisController = require('../controllers/workAnalysisController');
|
||||
|
||||
// 🏠 대시보드용 종합 데이터 (가장 많이 사용될 것 같아서 맨 위에)
|
||||
router.get('/dashboard', workAnalysisController.getDashboardData);
|
||||
|
||||
// 📊 기본 통계
|
||||
router.get('/stats', workAnalysisController.getStats);
|
||||
|
||||
// 📈 일별 작업시간 추이
|
||||
router.get('/daily-trend', workAnalysisController.getDailyTrend);
|
||||
|
||||
// 👥 작업자별 통계
|
||||
router.get('/worker-stats', workAnalysisController.getWorkerStats);
|
||||
|
||||
// 📋 프로젝트별 통계
|
||||
router.get('/project-stats', workAnalysisController.getProjectStats);
|
||||
|
||||
// 🔧 작업유형별 통계
|
||||
router.get('/work-type-stats', workAnalysisController.getWorkTypeStats);
|
||||
|
||||
// 🕐 최근 작업 현황
|
||||
router.get('/recent-work', workAnalysisController.getRecentWork);
|
||||
|
||||
// 📅 요일별 패턴 분석
|
||||
router.get('/weekday-pattern', workAnalysisController.getWeekdayPattern);
|
||||
|
||||
// ❌ 에러 분석
|
||||
router.get('/error-analysis', workAnalysisController.getErrorAnalysis);
|
||||
|
||||
// 📊 월별 비교 분석
|
||||
router.get('/monthly-comparison', workAnalysisController.getMonthlyComparison);
|
||||
|
||||
// 🎯 작업자별 전문분야 분석
|
||||
router.get('/worker-specialization', workAnalysisController.getWorkerSpecialization);
|
||||
|
||||
// 📋 헬스체크 및 API 정보
|
||||
router.get('/health', (req, res) => {
|
||||
res.json({
|
||||
success: true,
|
||||
message: '작업 분석 API가 정상 작동 중입니다.',
|
||||
endpoints: [
|
||||
'GET /work-analysis/dashboard - 대시보드 종합 데이터',
|
||||
'GET /work-analysis/stats - 기본 통계',
|
||||
'GET /work-analysis/daily-trend - 일별 추이',
|
||||
'GET /work-analysis/worker-stats - 작업자별 통계',
|
||||
'GET /work-analysis/project-stats - 프로젝트별 통계',
|
||||
'GET /work-analysis/work-type-stats - 작업유형별 통계',
|
||||
'GET /work-analysis/recent-work - 최근 작업 현황',
|
||||
'GET /work-analysis/weekday-pattern - 요일별 패턴',
|
||||
'GET /work-analysis/error-analysis - 에러 분석',
|
||||
'GET /work-analysis/monthly-comparison - 월별 비교',
|
||||
'GET /work-analysis/worker-specialization - 작업자 전문분야'
|
||||
],
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
26
api.hyungi.net/routes/workReportRoutes.js
Normal file
26
api.hyungi.net/routes/workReportRoutes.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const workReportController = require('../controllers/workReportController');
|
||||
|
||||
// CREATE
|
||||
router.post('/', workReportController.createWorkReport);
|
||||
|
||||
// READ BY DATE
|
||||
router.get('/date/:date', workReportController.getWorkReportsByDate);
|
||||
|
||||
// ✅ summary 라우트는 반드시 아래보다 위에 둬야 작동합니다
|
||||
router.get('/summary', workReportController.getSummary);
|
||||
|
||||
// READ IN RANGE
|
||||
router.get('/', workReportController.getWorkReportsInRange);
|
||||
|
||||
// READ ONE (항상 가장 마지막)
|
||||
router.get('/:id', workReportController.getWorkReportById);
|
||||
|
||||
// UPDATE
|
||||
router.put('/:id', workReportController.updateWorkReport);
|
||||
|
||||
// DELETE
|
||||
router.delete('/:id', workReportController.removeWorkReport);
|
||||
|
||||
module.exports = router;
|
||||
20
api.hyungi.net/routes/workerRoutes.js
Normal file
20
api.hyungi.net/routes/workerRoutes.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const workerController = require('../controllers/workerController');
|
||||
|
||||
// 작업자 생성
|
||||
router.post('/', workerController.createWorker);
|
||||
|
||||
// 전체 작업자 조회
|
||||
router.get('/', workerController.getAllWorkers);
|
||||
|
||||
// 특정 작업자 조회
|
||||
router.get('/:worker_id', workerController.getWorkerById);
|
||||
|
||||
// 작업자 업데이트
|
||||
router.put('/:worker_id', workerController.updateWorker);
|
||||
|
||||
// 작업자 삭제
|
||||
router.delete('/:worker_id', workerController.removeWorker);
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user