import express from "express"; import { authenticateToken } from "../middleware/authMiddleware"; import { AuthenticatedRequest } from "../types/auth"; import { logger } from "../utils/logger"; import { FileSystemManager } from "../utils/fileSystemManager"; import { query, queryOne } from "../database/db"; const router = express.Router(); // 모든 라우트에 인증 미들웨어 적용 router.use(authenticateToken); /** * DELETE /api/company-management/:companyCode * 회사 삭제 및 파일 정리 */ router.delete( "/:companyCode", async (req: AuthenticatedRequest, res): Promise => { try { const { companyCode } = req.params; const { createBackup = true } = req.body; logger.info("회사 삭제 요청", { companyCode, createBackup, userId: req.user?.userId, }); // 1. 회사 존재 확인 const existingCompany = await queryOne( `SELECT * FROM company_mng WHERE company_code = $1`, [companyCode] ); if (!existingCompany) { res.status(404).json({ success: false, message: "존재하지 않는 회사입니다.", errorCode: "COMPANY_NOT_FOUND", }); return; } // 2. 회사 파일 정리 (백업 또는 삭제) try { await FileSystemManager.cleanupCompanyFiles(companyCode, createBackup); logger.info("회사 파일 정리 완료", { companyCode, createBackup }); } catch (fileError) { logger.error("회사 파일 정리 실패", { companyCode, error: fileError }); res.status(500).json({ success: false, message: "회사 파일 정리 중 오류가 발생했습니다.", error: fileError instanceof Error ? fileError.message : "Unknown error", }); return; } // 3. 데이터베이스에서 회사 삭제 (soft delete) await query( `UPDATE company_mng SET status = 'deleted' WHERE company_code = $1`, [companyCode] ); logger.info("회사 삭제 완료", { companyCode, companyName: existingCompany.company_name, deletedBy: req.user?.userId, }); res.json({ success: true, message: `회사 '${existingCompany.company_name}'이(가) 성공적으로 삭제되었습니다.`, data: { companyCode, companyName: existingCompany.company_name, backupCreated: createBackup, deletedAt: new Date().toISOString(), }, }); } catch (error) { logger.error("회사 삭제 실패", { error, companyCode: req.params.companyCode, }); res.status(500).json({ success: false, message: "회사 삭제 중 오류가 발생했습니다.", error: error instanceof Error ? error.message : "Unknown error", }); } } ); /** * GET /api/company-management/:companyCode/disk-usage * 회사별 디스크 사용량 조회 */ router.get( "/:companyCode/disk-usage", async (req: AuthenticatedRequest, res): Promise => { try { const { companyCode } = req.params; const diskUsage = FileSystemManager.getCompanyDiskUsage(companyCode); res.json({ success: true, data: { companyCode, fileCount: diskUsage.fileCount, totalSize: diskUsage.totalSize, totalSizeMB: Math.round((diskUsage.totalSize / 1024 / 1024) * 100) / 100, lastChecked: new Date().toISOString(), }, }); } catch (error) { logger.error("디스크 사용량 조회 실패", { error, companyCode: req.params.companyCode, }); res.status(500).json({ success: false, message: "디스크 사용량 조회 중 오류가 발생했습니다.", error: error instanceof Error ? error.message : "Unknown error", }); } } ); /** * GET /api/company-management/disk-usage/all * 전체 회사 디스크 사용량 조회 */ router.get( "/disk-usage/all", async (req: AuthenticatedRequest, res): Promise => { try { const allUsage = FileSystemManager.getAllCompaniesDiskUsage(); const totalStats = allUsage.reduce( (acc, company) => ({ totalFiles: acc.totalFiles + company.fileCount, totalSize: acc.totalSize + company.totalSize, }), { totalFiles: 0, totalSize: 0 } ); res.json({ success: true, data: { companies: allUsage.map((company) => ({ ...company, totalSizeMB: Math.round((company.totalSize / 1024 / 1024) * 100) / 100, })), summary: { totalCompanies: allUsage.length, totalFiles: totalStats.totalFiles, totalSize: totalStats.totalSize, totalSizeMB: Math.round((totalStats.totalSize / 1024 / 1024) * 100) / 100, }, lastChecked: new Date().toISOString(), }, }); } catch (error) { logger.error("전체 디스크 사용량 조회 실패", { error }); res.status(500).json({ success: false, message: "전체 디스크 사용량 조회 중 오류가 발생했습니다.", error: error instanceof Error ? error.message : "Unknown error", }); } } ); export default router;