// 공차중계 운전자 컨트롤러 import { Response } from "express"; import { query } from "../database/db"; import { logger } from "../utils/logger"; import { AuthenticatedRequest } from "../types/auth"; export class DriverController { /** * GET /api/driver/profile * 운전자 프로필 조회 */ static async getProfile(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user?.userId; if (!userId) { res.status(401).json({ success: false, message: "인증이 필요합니다.", }); return; } // 사용자 정보 조회 const userResult = await query( `SELECT user_id, user_name, cell_phone, license_number, vehicle_number, signup_type, branch_name FROM user_info WHERE user_id = $1`, [userId] ); if (userResult.length === 0) { res.status(404).json({ success: false, message: "사용자를 찾을 수 없습니다.", }); return; } const user = userResult[0]; // 공차중계 사용자가 아닌 경우 if (user.signup_type !== "DRIVER") { res.status(403).json({ success: false, message: "공차중계 사용자만 접근할 수 있습니다.", }); return; } // 차량 정보 조회 const vehicleResult = await query( `SELECT vehicle_number, vehicle_type, driver_name, driver_phone, status FROM vehicles WHERE user_id = $1`, [userId] ); const vehicle = vehicleResult.length > 0 ? vehicleResult[0] : null; res.status(200).json({ success: true, data: { userId: user.user_id, userName: user.user_name, phoneNumber: user.cell_phone, licenseNumber: user.license_number, vehicleNumber: user.vehicle_number, vehicleType: vehicle?.vehicle_type || null, vehicleStatus: vehicle?.status || null, branchName: user.branch_name || null, }, }); } catch (error) { logger.error("운전자 프로필 조회 오류:", error); res.status(500).json({ success: false, message: "프로필 조회 중 오류가 발생했습니다.", }); } } /** * PUT /api/driver/profile * 운전자 프로필 수정 (이름, 연락처, 면허정보, 차량번호, 차종) */ static async updateProfile(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user?.userId; if (!userId) { res.status(401).json({ success: false, message: "인증이 필요합니다.", }); return; } const { userName, phoneNumber, licenseNumber, vehicleNumber, vehicleType, branchName } = req.body; // 공차중계 사용자 확인 const userCheck = await query( `SELECT signup_type, vehicle_number FROM user_info WHERE user_id = $1`, [userId] ); if (userCheck.length === 0) { res.status(404).json({ success: false, message: "사용자를 찾을 수 없습니다.", }); return; } if (userCheck[0].signup_type !== "DRIVER") { res.status(403).json({ success: false, message: "공차중계 사용자만 접근할 수 있습니다.", }); return; } const oldVehicleNumber = userCheck[0].vehicle_number; // 차량번호 변경 시 중복 확인 if (vehicleNumber && vehicleNumber !== oldVehicleNumber) { const duplicateCheck = await query( `SELECT vehicle_number FROM vehicles WHERE vehicle_number = $1 AND user_id != $2`, [vehicleNumber, userId] ); if (duplicateCheck.length > 0) { res.status(400).json({ success: false, message: "이미 등록된 차량번호입니다.", }); return; } } // user_info 업데이트 await query( `UPDATE user_info SET user_name = COALESCE($1, user_name), cell_phone = COALESCE($2, cell_phone), license_number = COALESCE($3, license_number), vehicle_number = COALESCE($4, vehicle_number), branch_name = COALESCE($5, branch_name) WHERE user_id = $6`, [userName || null, phoneNumber || null, licenseNumber || null, vehicleNumber || null, branchName || null, userId] ); // vehicles 테이블 업데이트 await query( `UPDATE vehicles SET vehicle_number = COALESCE($1, vehicle_number), vehicle_type = COALESCE($2, vehicle_type), driver_name = COALESCE($3, driver_name), driver_phone = COALESCE($4, driver_phone), branch_name = COALESCE($5, branch_name), updated_at = NOW() WHERE user_id = $6`, [vehicleNumber || null, vehicleType || null, userName || null, phoneNumber || null, branchName || null, userId] ); logger.info(`운전자 프로필 수정 완료: ${userId}`); res.status(200).json({ success: true, message: "프로필이 수정되었습니다.", }); } catch (error) { logger.error("운전자 프로필 수정 오류:", error); res.status(500).json({ success: false, message: "프로필 수정 중 오류가 발생했습니다.", }); } } /** * PUT /api/driver/status * 차량 상태 변경 (대기/정비만 가능) */ static async updateStatus(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user?.userId; if (!userId) { res.status(401).json({ success: false, message: "인증이 필요합니다.", }); return; } const { status } = req.body; // 허용된 상태값만 (대기: off, 정비: maintenance) const allowedStatuses = ["off", "maintenance"]; if (!status || !allowedStatuses.includes(status)) { res.status(400).json({ success: false, message: "유효하지 않은 상태값입니다. (off: 대기, maintenance: 정비)", }); return; } // 공차중계 사용자 확인 const userCheck = await query( `SELECT signup_type FROM user_info WHERE user_id = $1`, [userId] ); if (userCheck.length === 0 || userCheck[0].signup_type !== "DRIVER") { res.status(403).json({ success: false, message: "공차중계 사용자만 접근할 수 있습니다.", }); return; } // vehicles 테이블 상태 업데이트 const updateResult = await query( `UPDATE vehicles SET status = $1, updated_at = NOW() WHERE user_id = $2`, [status, userId] ); logger.info(`차량 상태 변경: ${userId} -> ${status}`); res.status(200).json({ success: true, message: `차량 상태가 ${status === "off" ? "대기" : "정비"}로 변경되었습니다.`, }); } catch (error) { logger.error("차량 상태 변경 오류:", error); res.status(500).json({ success: false, message: "상태 변경 중 오류가 발생했습니다.", }); } } /** * DELETE /api/driver/vehicle * 차량 삭제 (user_id = NULL 처리, 기록 보존) */ static async deleteVehicle(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user?.userId; if (!userId) { res.status(401).json({ success: false, message: "인증이 필요합니다.", }); return; } // 공차중계 사용자 확인 const userCheck = await query( `SELECT signup_type, vehicle_number FROM user_info WHERE user_id = $1`, [userId] ); if (userCheck.length === 0 || userCheck[0].signup_type !== "DRIVER") { res.status(403).json({ success: false, message: "공차중계 사용자만 접근할 수 있습니다.", }); return; } // vehicles 테이블에서 user_id를 NULL로 변경하고 status를 disabled로 (기록 보존) await query( `UPDATE vehicles SET user_id = NULL, status = 'disabled', updated_at = NOW() WHERE user_id = $1`, [userId] ); // user_info에서 vehicle_number를 NULL로 변경 await query( `UPDATE user_info SET vehicle_number = NULL WHERE user_id = $1`, [userId] ); logger.info(`차량 삭제 완료 (기록 보존): ${userId}`); res.status(200).json({ success: true, message: "차량이 삭제되었습니다.", }); } catch (error) { logger.error("차량 삭제 오류:", error); res.status(500).json({ success: false, message: "차량 삭제 중 오류가 발생했습니다.", }); } } /** * POST /api/driver/vehicle * 새 차량 등록 */ static async registerVehicle(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user?.userId; const companyCode = req.user?.companyCode; if (!userId) { res.status(401).json({ success: false, message: "인증이 필요합니다.", }); return; } const { vehicleNumber, vehicleType, branchName } = req.body; if (!vehicleNumber) { res.status(400).json({ success: false, message: "차량번호는 필수입니다.", }); return; } // 공차중계 사용자 확인 const userCheck = await query( `SELECT signup_type, user_name, cell_phone, vehicle_number, company_code FROM user_info WHERE user_id = $1`, [userId] ); if (userCheck.length === 0 || userCheck[0].signup_type !== "DRIVER") { res.status(403).json({ success: false, message: "공차중계 사용자만 접근할 수 있습니다.", }); return; } // 이미 차량이 있는지 확인 if (userCheck[0].vehicle_number) { res.status(400).json({ success: false, message: "이미 등록된 차량이 있습니다. 먼저 기존 차량을 삭제해주세요.", }); return; } // 차량번호 중복 확인 const duplicateCheck = await query( `SELECT vehicle_number FROM vehicles WHERE vehicle_number = $1 AND user_id IS NOT NULL`, [vehicleNumber] ); if (duplicateCheck.length > 0) { res.status(400).json({ success: false, message: "이미 등록된 차량번호입니다.", }); return; } const userName = userCheck[0].user_name; const userPhone = userCheck[0].cell_phone; // 사용자의 company_code 사용 (req.user에서 가져오거나 DB에서 조회한 값 사용) const userCompanyCode = companyCode || userCheck[0].company_code; // vehicles 테이블에 새 차량 등록 (company_code 포함, status는 'off') await query( `INSERT INTO vehicles (vehicle_number, vehicle_type, user_id, driver_name, driver_phone, branch_name, status, company_code, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, 'off', $7, NOW(), NOW())`, [vehicleNumber, vehicleType || null, userId, userName, userPhone, branchName || null, userCompanyCode] ); // user_info에 vehicle_number 업데이트 await query( `UPDATE user_info SET vehicle_number = $1 WHERE user_id = $2`, [vehicleNumber, userId] ); logger.info(`새 차량 등록 완료: ${userId} -> ${vehicleNumber} (company_code: ${userCompanyCode})`); res.status(200).json({ success: true, message: "차량이 등록되었습니다.", }); } catch (error) { logger.error("차량 등록 오류:", error); res.status(500).json({ success: false, message: "차량 등록 중 오류가 발생했습니다.", }); } } /** * DELETE /api/driver/account * 회원 탈퇴 (차량 정보 포함 삭제) */ static async deleteAccount(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user?.userId; if (!userId) { res.status(401).json({ success: false, message: "인증이 필요합니다.", }); return; } // 공차중계 사용자 확인 const userCheck = await query( `SELECT signup_type FROM user_info WHERE user_id = $1`, [userId] ); if (userCheck.length === 0) { res.status(404).json({ success: false, message: "사용자를 찾을 수 없습니다.", }); return; } if (userCheck[0].signup_type !== "DRIVER") { res.status(403).json({ success: false, message: "공차중계 사용자만 탈퇴할 수 있습니다.", }); return; } // vehicles 테이블에서 삭제 await query(`DELETE FROM vehicles WHERE user_id = $1`, [userId]); // user_info 테이블에서 삭제 await query(`DELETE FROM user_info WHERE user_id = $1`, [userId]); logger.info(`회원 탈퇴 완료: ${userId}`); res.status(200).json({ success: true, message: "회원 탈퇴가 완료되었습니다.", }); } catch (error) { logger.error("회원 탈퇴 오류:", error); res.status(500).json({ success: false, message: "회원 탈퇴 처리 중 오류가 발생했습니다.", }); } } }