Files
tk-factory-services/system1-factory/api/routes/userRoutes.js
Hyungi Ahn 93edf9529a refactor: 보안 취약점 제거 + 데드코드 정리 + 프론트엔드 중복 통합
- 인증 없는 임시 엔드포인트 삭제 (index.js, healthRoutes.js, publicPaths)
- skipAuth 우회 라우트 삭제 (workAnalysis.js)
- 하드코딩 유저 백도어 삭제 (routes/auth.js)
- 안전체크 CRUD에 admin 권한 추가 (tbmRoutes.js)
- deprecated shim 3개 삭제 + 8개 소비 파일 import 정리 (auth.js 직접 참조)
- 미사용 pageAccessController, db.js, common/security.js 삭제
- escapeHtml() 5곳 로컬 중복 제거 → api-base.js 전역 사용
- userPageAccess_v2_v2 캐시 키 버그 수정 (app-init.js)
- system3 .bak 파일 삭제, PROGRESS.md 업데이트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 08:19:01 +09:00

154 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 사용자 관리 라우터
*
* 사용자 CRUD 및 상태 관리를 위한 API 라우트 정의
*
* @author TK-FB-Project
* @since 2025-12-11
*/
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const { verifyToken } = require('../middlewares/auth');
const logger = require('../utils/logger');
/**
* 모든 라우트에 인증 미들웨어 적용
*/
router.use(verifyToken);
/**
* 관리자 권한 확인 미들웨어
* role 또는 access_level로 관리자 확인
*/
const adminOnly = (req, res, next) => {
const userRole = req.user?.role?.toLowerCase();
const accessLevel = req.user?.access_level?.toLowerCase();
// role 기반 확인
const isAdminByRole = userRole === 'admin' || userRole === 'system' || userRole === 'system admin';
// access_level 기반 확인 (role이 없는 경우 대비)
const isAdminByAccessLevel = accessLevel === 'admin' || accessLevel === 'system';
if (req.user && (isAdminByRole || isAdminByAccessLevel)) {
next();
} else {
logger.warn('관리자 권한 없는 접근 시도', {
userId: req.user?.user_id,
username: req.user?.username,
role: req.user?.role,
accessLevel: req.user?.access_level,
url: req.originalUrl
});
return res.status(403).json({
success: false,
message: '관리자 권한이 필요합니다'
});
}
};
// ========== 개인 정보 조회 API (관리자 권한 불필요) ==========
// 내 정보 조회
router.get('/me', userController.getMyInfo || ((req, res) => res.json({ success: true, data: req.user })));
// 내 출근 기록 조회
router.get('/me/attendance-records', async (req, res) => {
try {
const { year, month } = req.query;
const AttendanceModel = require('../models/attendanceModel');
const startDate = `${year}-${String(month).padStart(2, '0')}-01`;
const endDate = `${year}-${String(month).padStart(2, '0')}-31`;
const records = await AttendanceModel.getDailyRecords(startDate, endDate, req.user.worker_id);
res.json({ success: true, data: records });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// 내 연차 잔액 조회
router.get('/me/vacation-balance', async (req, res) => {
try {
const AttendanceModel = require('../models/attendanceModel');
const year = req.query.year || new Date().getFullYear();
const balance = await AttendanceModel.getWorkerVacationBalance(req.user.worker_id, year);
res.json({ success: true, data: balance });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// 내 작업 보고서 조회
router.get('/me/work-reports', async (req, res) => {
try {
const { startDate, endDate } = req.query;
const db = require('../config/database');
const reports = await db.query(
'SELECT * FROM daily_work_reports WHERE worker_id = ? AND report_date BETWEEN ? AND ? ORDER BY report_date DESC',
[req.user.worker_id, startDate, endDate]
);
res.json({ success: true, data: reports });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// 내 월별 통계
router.get('/me/monthly-stats', async (req, res) => {
try {
const { year, month } = req.query;
const { getDb } = require('../dbPool');
const db = await getDb();
const [stats] = await db.execute(
`SELECT
SUM(total_work_hours) as month_hours,
COUNT(DISTINCT record_date) as work_days
FROM daily_attendance_records
WHERE worker_id = ? AND YEAR(record_date) = ? AND MONTH(record_date) = ?`,
[req.user.worker_id, year, month]
);
res.json({ success: true, data: stats[0] || { month_hours: 0, work_days: 0 } });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// ========== 페이지 권한 조회는 pageAccessRoutes.js에서 처리 ==========
// GET /:id/page-access → /api/users/:userId/page-access (pageAccessRoutes.js)
// tkuser의 user_page_permissions 테이블을 조회하는 통합 핸들러 사용
// ========== 관리자 전용 API ==========
/**
* 모든 라우트에 관리자 권한 적용
*/
router.use(adminOnly);
// 📋 사용자 목록 조회
router.get('/', userController.getAllUsers);
// 👤 특정 사용자 조회
router.get('/:id', userController.getUserById);
// 새 사용자 생성
router.post('/', userController.createUser);
// ✏️ 사용자 정보 수정
router.put('/:id', userController.updateUser);
// 🔄 사용자 상태 변경
router.put('/:id/status', userController.updateUserStatus);
// 🔑 사용자 비밀번호 초기화 (000000)
router.post('/:id/reset-password', userController.resetUserPassword);
// 🗑️ 사용자 비활성화 (Soft Delete)
router.delete('/:id', userController.deleteUser);
// 💀 사용자 영구 삭제 (Hard Delete)
router.delete('/:id/permanent', userController.permanentDeleteUser);
// 🔐 사용자 페이지 접근 권한 업데이트 (Admin만)
router.put('/:id/page-access', userController.updateUserPageAccess);
module.exports = router;