[RAPID] feat: 메신저 기능 구현 (Socket.IO 실시간 채팅)

- DB: messenger_rooms/participants/messages/reactions/files 테이블 생성
- Backend: REST API 9개 엔드포인트 + Socket.IO 실시간 핸들러
- Frontend: Gmail 스타일 FAB + 모달, 채팅방 목록, 채팅 패널
- 기능: DM/그룹/채널, 파일 첨부, 이모지 리액션, 멘션, 스레드
- 알림: 토스트 on/off 토글, FAB 읽지 않은 배지

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

[RAPID-fix] 메신저 API snake_case→camelCase 변환 및 Socket.IO URL 수정

- useRooms/useMessages/useCompanyUsers 훅에서 DB 응답 camelCase 변환
- Socket.IO 기본 연결 URL 3001 → 8080 수정
- runMigration.ts 마이그레이션 파일 경로 수정 (../../ → ../../../)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

[RAPID-fix] 방 생성 API camelCase/snake_case 호환 처리

- createRoom 컨트롤러에서 participantIds/type/name (camelCase) fallback 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

[RAPID-fix] 메시지 전송 API 추가 (sendMessage 라우트/컨트롤러 누락)

- POST /api/messenger/rooms/:roomId/messages 라우트 등록
- MessengerController.sendMessage 메서드 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-30 18:05:54 +09:00
parent e763249342
commit f558073ef8
28 changed files with 2578 additions and 10 deletions

View File

@@ -136,6 +136,7 @@ import inspectionResultRoutes from "./routes/inspectionResultRoutes"; // POP 검
import vehicleTripRoutes from "./routes/vehicleTripRoutes"; // 차량 운행 이력 관리
import approvalRoutes from "./routes/approvalRoutes"; // 결재 시스템
import userMailRoutes from "./routes/userMailRoutes"; // 사용자 메일 계정
import messengerRoutes from "./routes/messengerRoutes"; // 메신저
import driverRoutes from "./routes/driverRoutes"; // 공차중계 운전자 관리
import taxInvoiceRoutes from "./routes/taxInvoiceRoutes"; // 세금계산서 관리
import cascadingRelationRoutes from "./routes/cascadingRelationRoutes"; // 연쇄 드롭다운 관계 관리
@@ -383,6 +384,7 @@ app.use("/api/ai/v1", aiAssistantProxy); // AI 어시스턴트 (동일 서비스
app.use("/api/vehicle", vehicleTripRoutes); // 차량 운행 이력 관리
app.use("/api/approval", approvalRoutes); // 결재 시스템
app.use("/api/user-mail", userMailRoutes); // 사용자 메일 계정
app.use("/api/messenger", messengerRoutes); // 메신저
// app.use("/api/collections", collectionRoutes); // 임시 주석
// app.use("/api/batch", batchRoutes); // 임시 주석
// app.use('/api/users', userRoutes);
@@ -410,6 +412,20 @@ const server = app.listen(PORT, HOST, async () => {
logger.info(`🔗 Health check: http://${HOST}:${PORT}/health`);
logger.info(`🌐 External access: http://39.117.244.52:${PORT}/health`);
// Socket.IO initialization
try {
const { Server: SocketIOServer } = await import("socket.io");
const { initMessengerSocket } = await import("./socket/messengerSocket");
const io = new SocketIOServer(server, {
cors: { origin: "*", methods: ["GET", "POST"] },
path: "/socket.io",
});
initMessengerSocket(io);
logger.info("💬 Socket.IO messenger initialized");
} catch (error) {
logger.error("❌ Socket.IO initialization failed:", error);
}
// 비동기 초기화 작업 (에러가 발생해도 서버는 유지)
initializeServices().catch(err => {
logger.error('❌ 서비스 초기화 중 치명적 에러 발생:', err);
@@ -426,6 +442,7 @@ async function initializeServices() {
runDtgManagementLogMigration,
runApprovalSystemMigration,
runUserMailAccountsMigration,
runMessengerMigration,
} = await import("./database/runMigration");
await runDashboardMigration();
@@ -433,6 +450,7 @@ async function initializeServices() {
await runDtgManagementLogMigration();
await runApprovalSystemMigration();
await runUserMailAccountsMigration();
await runMessengerMigration();
} catch (error) {
logger.error(`❌ 마이그레이션 실패:`, error);
}