diff --git a/.gitignore b/.gitignore
index 241c0f6e54e4da30c80a69c553d9d43e5b04f2fd..c95fa60cf8457ba1592eea59de29eea125ba3f81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,8 @@
 node_modules/
 .env
 config.json/
+resources/
+app.js
+output.log
+weblog.log
+
diff --git a/app.js b/app.js
index 952e375ab1eefe8e4640271668cb1ca136c36754..7fa87fe075aff37349a506b093ba73a52d104798 100644
--- a/app.js
+++ b/app.js
@@ -16,45 +16,54 @@ const app = express();
 
 
 app.use(morgan('dev'));  //로깅용
-// CORS 설정
+
+// CORS 설정 (로컬 환경용)
 app.use(
   cors({
-    origin: 'http://localhost:3000', 
+    origin:[ process.env.FROENT_URL,'https://yanawa.shop'],
     methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
     allowedHeaders: ['Content-Type', 'Authorization'],
-    credentials: true,
+    credentials: true, 
   })
 );
-
-
-// 미들웨어 설정
-app.use(express.json());
-app.use(express.urlencoded({ extended: false }));
-
-// 세션 설정
+// 
 app.use(
   session({
-    secret: 'your_session_secret', 
+    secret: 'your-secret-key',
     resave: false,
     saveUninitialized: false,
+    rolling: true,
+    cookie: {
+      httpOnly: true,
+      secure: true, 
+      maxAge: 60 * 60 * 1000, // 1시간
+      sameSite: 'none', 
+    },
   })
 );
 
+// 미들웨어 설정
+app.use(express.json());
+app.use(express.urlencoded({ extended: false }));
+
 // Passport 초기화 및 세션 연결
 app.use(passport.initialize());
 app.use(passport.session());
 
 
 app.use(flash());
+
+
+app.set('trust proxy', 1);
 console.log('MongoDB URI:', process.env.MONGO_URI);
 //라우터 등록 
-const authRoutes = require('./routes/auth');
-app.use('/auth', authRoutes);
+const authRoutes = require('./routes/authRoute');
+app.use('/api/auth', authRoutes);
 
-const scheduleRoutes = require('./routes/schedule');
+const scheduleRoutes = require('./routes/scheduleRoute');
 app.use('/api/schedule', scheduleRoutes);
 
-const friendRoutes = require('./routes/friend');
+const friendRoutes = require('./routes/friendRoute');
 app.use('/api/friend', friendRoutes);
 
 const meetingRoutes = require('./routes/meetingRoute');
@@ -66,6 +75,9 @@ app.use('/api/chat', chatRoutes);
 const memberRoutes = require('./routes/memberRoute');
 app.use('/api/member', memberRoutes);
 
+const sessionRouter = require('./routes/sessionRoute');
+app.use('/api/session', sessionRouter);
+
 // 스케줄 클리너 초기화
 initScheduleCleaner();
 
@@ -86,4 +98,4 @@ const PORT = process.env.PORT || 3000;
     console.error('❌ 서버 시작 중 오류 발생:', error);
     process.exit(1);
   }
-})();
\ No newline at end of file
+})();
diff --git a/controllers/chatController.js b/controllers/chatController.js
index 41a2d3c6f05d4f021964785d98414452322050ec..bfcca38df3a7ab0b513d3c4bee2c46533226b09b 100644
--- a/controllers/chatController.js
+++ b/controllers/chatController.js
@@ -91,4 +91,67 @@ exports.updateStatusAndLogId = async (req, res) => {
     console.error('Error updating user status and lastReadLogId:', err);
     res.status(500).json({ error: 'Failed to update user status and lastReadLogId' });
   }
+};
+
+// 공지 등록
+exports.addNotice = async (req, res) => {
+  const { chatRoomId } = req.params;
+  const { sender, message } = req.body;
+
+  try {
+    const notice = await chatService.addNotice(chatRoomId, sender, message);
+    res.status(200).json(notice);
+  } catch (error) {
+    console.error('Error adding notice:', error.message);
+    res.status(500).json({ error: 'Failed to add notice' });
+  }
+};
+
+// 최신 공지 조회
+exports.getLatestNotice = async (req, res) => {
+  const { chatRoomId } = req.params;
+
+  try {
+    const latestNotice = await chatService.getLatestNotice(chatRoomId);
+    if (latestNotice) {
+      res.status(200).json(latestNotice);
+    } else {
+      res.status(404).json({ message: 'No notices found' });
+    }
+  } catch (error) {
+    console.error('Error fetching latest notice:', error.message);
+    res.status(500).json({ error: 'Failed to fetch latest notice' });
+  }
+};
+
+// 공지 전체 조회
+exports.getAllNotices = async (req, res) => {
+  const { chatRoomId } = req.params;
+
+  try {
+    const notices = await chatService.getAllNotices(chatRoomId);
+    console.log(`[getAllNotices] Notices for chatRoomId ${chatRoomId}:`, notices); // 로그 추가
+    res.status(200).json(notices);
+  } catch (error) {
+    console.error('Error fetching all notices:', error.message);
+    res.status(500).json({ error: 'Failed to fetch all notices' });
+  }
+};
+
+// 공지사항 상세 조회
+exports.getNoticeById = async (req, res) => {
+  const { chatRoomId, noticeId } = req.params;
+
+  try {
+    const notice = await chatService.getNoticeById(chatRoomId, noticeId);
+
+    if (!notice) {
+      return res.status(404).json({ error: 'Notice not found' });
+    }
+
+    res.status(200).json(notice);
+  } catch (error) {
+    console.error('Error fetching notice by ID:', error.message);
+    res.status(500).json({ error: 'Failed to fetch notice by ID' });
+  }
 };
\ No newline at end of file
diff --git a/controllers/friendController.js b/controllers/friendController.js
index ce50caf5463a7095f3516a27fc14c7a0c114f7f4..09cbf577aa6ce94f6e9bc4ac52d902c5d97e6ae5 100644
--- a/controllers/friendController.js
+++ b/controllers/friendController.js
@@ -1,53 +1,59 @@
 const FriendService = require('../services/friendService');
 const { User } = require('../models');
+const performanceMonitor = require('../utils/performanceMonitor');
 
 class friendController {
-        /**
-         * 친구 요청 보내기
-         * 클라이언트는 userId와 요청을 보낼 사용자의 email을 전송
-         */
-        async sendFriendRequest(req, res, next) {
-            const { userId, email } = req.body;
-    
-            try {
+    /**
+     * 친구 요청 보내기
+     * 클라이언트는 userId와 요청을 보낼 사용자의 email을 전송
+     * POST /api/friend/request
+     * 
+     */
+    async sendFriendRequest(req, res) {
+        try {
+            return await performanceMonitor.measureAsync('sendFriendRequest', async () => {
+                const email  = req.body;
+                const userId = req.user.id;
 
                 if (!userId || !email) {
-                    return res.status(400).json({ message: 'userId와 email은 필수 입력 항목입니다.' });
+                    throw new Error('userId와 email은 필수 입력 항목입니다.');
                 }
-                // 친구 요청을 받을 사용자의 정보 조회 (서비스로 분리할지 생각)
-                const receiver = await User.findOne({ where: { email: email } });
+
+                const receiver = await User.findOne({ where: { email } });
                 if (!receiver) {
-                    return res.status(404).json({ message: '요청을 받을 사용자를 찾을 수 없습니다.' });
+                    throw new Error('요청을 받을 사용자를 찾을 수 없습니다.');
                 }
-                const friendId = receiver.id;
-                // 친구 요청 보내기 서비스 호출
-                const friendRequest = await FriendService.sendFriendRequest(userId, friendId);
+
+                const friendRequest = await FriendService.sendFriendRequest(userId, receiver.id);
                 return res.status(201).json({
-                    success:true,
-                    data:friendRequest
+                    success: true,
+                    data: friendRequest
                 });
-            } catch (error) {
-                // 유니크 제약조건 오류 처리
-                if (error.message === 'Friend request already exists') {
-                    return res.status(409).json({ message: error.message });
+            });
+        } catch (error) {
+            return res.status(error.status || 500).json({
+                success: false,
+                error: {
+                    message: error.message,
+                    code: 'FRIEND_REQUEST_ERROR'
                 }
-
-                // 일반 오류 처리
-                return res.status(500).json({ message: '서버 오류가 발생했습니다.', error: error.message });
-            }
+            });
         }
+    }
+
     /**
      * 받은 친구 요청 목록 조회
      * GET /api/friend/requests/received
      */
     async getReceivedRequests(req, res) {
         try {
-            const userId = req.user.id;
-            const requests = await FriendService.getReceivedRequests(userId);
-
-            return res.status(200).json({
-                success: true,
-                data: requests
+            return await performanceMonitor.measureAsync('getReceivedRequests', async () => {
+                const userId = req.user.id;
+                const requests = await FriendService.getReceivedRequests(userId);
+                return res.status(200).json({
+                    success: true,
+                    data: requests
+                });
             });
         } catch (error) {
             return res.status(500).json({
@@ -66,12 +72,13 @@ class friendController {
      */
     async getSentRequests(req, res) {
         try {
-            const userId = req.user.id;
-            const requests = await FriendService.getSentRequests(userId);
-
-            return res.status(200).json({
-                success: true,
-                data: requests
+            return await performanceMonitor.measureAsync('getSentRequests', async () => {
+                const userId = req.user.id;
+                const requests = await FriendService.getSentRequests(userId);
+                return res.status(200).json({
+                    success: true,
+                    data: requests
+                });
             });
         } catch (error) {
             return res.status(500).json({
@@ -83,21 +90,21 @@ class friendController {
             });
         }
     }
-    
     /**
      * 친구 요청 수락
      * POST /api/friend/request/:friendId/accept
      */
     async acceptRequest(req, res) {
         try {
-            const userId = req.user.id;
-            const { friendId } = req.params;
-
-            const result = await FriendService.acceptFriendRequest(userId, friendId);
-
-            return res.status(200).json({
-                success: true,
-                data: result
+            return await performanceMonitor.measureAsync('acceptFriendRequest', async () => {
+                const userId = req.user.id;
+                const { friendId } = req.params;
+
+                const result = await FriendService.acceptFriendRequest(userId, friendId);
+                return res.status(200).json({
+                    success: true,
+                    data: result
+                });
             });
         } catch (error) {
             return res.status(400).json({
@@ -116,14 +123,15 @@ class friendController {
      */
     async rejectRequest(req, res) {
         try {
-            const userId = req.user.id;
-            const { friendId } = req.params;
-
-            const result = await FriendService.rejectFriendRequest(userId, friendId);
-
-            return res.status(200).json({
-                success: true,
-                data: result
+            return await performanceMonitor.measureAsync('rejectFriendRequest', async () => {
+                const userId = req.user.id;
+                const { friendId } = req.params;
+
+                const result = await FriendService.rejectFriendRequest(userId, friendId);
+                return res.status(200).json({
+                    success: true,
+                    data: result
+                });
             });
         } catch (error) {
             return res.status(400).json({
@@ -142,23 +150,20 @@ class friendController {
      */
     async getFriendList(req, res) {
         try {
-            const userId = req.user.id;
-            const page = parseInt(req.query.page) || 0;
-            const size = parseInt(req.query.size) || 20;
-            
-            const friends = await FriendService.getFriendList(userId, {
-                limit: size,
-                offset: page * size
-            });
+            return await performanceMonitor.measureAsync('getFriendList', async () => {
+                const userId = req.user.id;
+                const page = parseInt(req.query.page) || 0;
+                const size = parseInt(req.query.size) || 20;
+
+                const friends = await FriendService.getFriendList(userId, {
+                    limit: size,
+                    offset: page * size
+                });
 
-            return res.status(200).json({
-                success: true,
-                data: {
-                    content: friends,
-                    page: page,
-                    size: size,
-                    hasNext: friends.length === size 
-                }
+                return res.status(200).json({
+                    success: true,
+                    data: friends
+                });
             });
         } catch (error) {
             return res.status(500).json({
@@ -177,17 +182,18 @@ class friendController {
      */
     async deleteFriend(req, res) {
         try {
-            const userId = req.user.id;
-            const { friendId } = req.params;
-
-            const result = await FriendService.deleteFriend(userId, friendId);
-
-            return res.status(200).json({
-                success: true,
-                data: {
-                    message: 'Friend deleted successfully',
-                    result: result
-                }
+            return await performanceMonitor.measureAsync('deleteFriend', async () => {
+                const userId = req.user.id;
+                const { friendId } = req.params;
+
+                const result = await FriendService.deleteFriend(userId, friendId);
+                return res.status(200).json({
+                    success: true,
+                    data: {
+                        message: 'Friend deleted successfully',
+                        result: result
+                    }
+                });
             });
         } catch (error) {
             return res.status(400).json({
diff --git a/controllers/meetingController.js b/controllers/meetingController.js
index 12ee66a740228e3ee825b171ef6df7a5d1060ccc..78f4464ff4d7bebb4c3a425ce3154bb4c1e5c042 100644
--- a/controllers/meetingController.js
+++ b/controllers/meetingController.js
@@ -14,7 +14,7 @@ class MeetingController {
      *     "time_idx_start": 40, // 예: 10:00 AM
      *     "time_idx_end": 42,   // 예: 10:30 AM
      *     "location": "회의실 A",
-     *     "deadline": "2024-04-25T23:59:59Z",
+     *     "deadline": "43",
      *     "type": "OPEN" // "OPEN" 또는 "CLOSE"
      *      "max_num":
      * }
@@ -116,6 +116,55 @@ class MeetingController {
             res.status(500).json({ error: err.message || '모임 상세 조회 실패' });
         }
     }
+
+    /**
+     * 내가 참여한 모임 목록 조회
+     * GET /api/meetings/my
+     */
+    async getMyMeetings(req, res) {
+        try {
+            const userId = req.user.id;
+            const page = parseInt(req.query.page) || 0;
+            const size = parseInt(req.query.size) || 20;
+
+            const meetings = await MeetingService.getMyMeetings(userId, {
+                limit: size,
+                offset: page * size
+            });
+
+            res.status(200).json({
+                success: true,
+                data: {
+                    content: meetings.content,
+                    page: page,
+                    size: size,
+                    hasNext: meetings.hasNext
+                }
+            });
+        } catch (err) {
+            console.error('내 모임 목록 조회 오류:', err);
+            res.status(500).json({ error: err.message || '내 모임 목록 조회 실패' });
+        }
+    }
+
+
+    /**
+     * 번개 모임 탈퇴
+     * DELETE /api/meeting/:meetingId/leave
+     */
+    async leaveMeeting(req, res) {
+        const { meetingId } = req.params;
+        const userId = req.user.id;
+
+        try {
+            await MeetingService.leaveMeeting(meetingId, userId);
+            res.status(200).json({ message: '모임 탈퇴 성공' });
+        } catch (err) {
+            console.error('모임 탈퇴 오류:', err);
+            res.status(500).json({ error: err.message || '모임 탈퇴 실패' });
+        }
+    }
+
 }
 
 module.exports = new MeetingController();
diff --git a/controllers/scheduleController.js b/controllers/scheduleController.js
index 4d43ee118a980c6ddf536eff25592f0cf734a66c..0855a84620a9c725abb490437de0f1a88b0d16e9 100644
--- a/controllers/scheduleController.js
+++ b/controllers/scheduleController.js
@@ -1,6 +1,7 @@
 // controllers/scheduleController.js
 const ScheduleService = require('../services/scheduleService');
 const ScheduleRequestDTO = require('../dtos/ScheduleRequestDTO');
+const performanceMonitor = require('../utils/performanceMonitor');
 
 class scheduleController {
     /**
@@ -21,24 +22,20 @@ class scheduleController {
      */
     async createSchedule(req, res) {
         try {
-            const userId = req.user.id;
-            const scheduleRequestDTO = new ScheduleRequestDTO(req.body);
-            const validatedData = scheduleRequestDTO.validate('create'); // 'create' 타입 검증
-
-            const { title, is_fixed, events } = validatedData;
-
-            const schedules = await ScheduleService.createSchedules({
-                userId,
-                title,
-                is_fixed,
-                events
-            });
+            return await performanceMonitor.measureAsync('createSchedule', async () => {
+                const userId = req.user.id;
+                const scheduleRequestDTO = new ScheduleRequestDTO(req.body);
+                const validatedData = scheduleRequestDTO.validate('create');
+
+                const schedule = await ScheduleService.createSchedules({
+                    userId,
+                    ...validatedData
+                });
 
-            return res.status(201).json({
-                success: true,
-                data: {
-                    schedules
-                }
+                return res.status(201).json({
+                    success: true,
+                    data: { schedule }
+                });
             });
         } catch (error) {
             return res.status(400).json({
@@ -49,7 +46,7 @@ class scheduleController {
                 }
             });
         }
-    }
+    }   
 
     /**
      * 스케줄 수정
@@ -57,31 +54,28 @@ class scheduleController {
      * Bulk update 지원
      * 요청 본문 예시:
      * {
-     *   updates: [
-     *     { time_idx: 36, title: 'New Title', is_fixed: true },
-     *     { time_idx: 44, title: 'Another Title' },
-     *     // ...
-     *   ]
+     *  "originalTitle": "알고리즘 스터디", // 기존 스케줄의 제목
+     *  "title": "알고리즘 스터디 2.0",     // 변경할 제목 (제목 변경 안할거면 기존 제목을 넣어야함 * -> title로 동일 스케줄을 찾아서)
+     *   "is_fixed": true,  
+     *   "time_indices": [36, 37, 38, 40]   // 변경할 time_indices 배열
      * }
      */
     async updateSchedules(req, res) {
         try {
-            const userId = req.user.id;
-            const scheduleRequestDTO = new ScheduleRequestDTO(req.body);
-            const validatedData = scheduleRequestDTO.validate('bulk_update'); // 'bulk_update' 타입 검증
+            return await performanceMonitor.measureAsync('updateSchedules', async () => {
+                const userId = req.user.id;
+                const scheduleRequestDTO = new ScheduleRequestDTO(req.body);
+                const validatedData = scheduleRequestDTO.validate('bulk_update');
 
-            const { updates } = validatedData;
+                const updatedSchedule = await ScheduleService.updateSchedules(userId, validatedData);
 
-            const updatedSchedules = await ScheduleService.updateSchedules(userId, updates);
-
-            return res.status(200).json({
-                success: true,
-                data: {
-                    schedules: updatedSchedules
-                }
+                return res.status(200).json({
+                    success: true,
+                    data: { schedule: updatedSchedule }
+                });
             });
         } catch (error) {
-            if (error.code === 'SCHEDULE_NOT_FOUND') {
+            if (error.message === 'Schedule not found') {
                 return res.status(404).json({
                     success: false,
                     error: {
@@ -106,25 +100,25 @@ class scheduleController {
      * Bulk delete 지원
      * 요청 본문 예시:
      * {
-     *   time_idxs: [36, 44, ...]
+     *  "title": "알고리즘 스터디"
      * }
      */
     async deleteSchedules(req, res) {
         try {
-            const userId = req.user.id;
-            const scheduleRequestDTO = new ScheduleRequestDTO(req.body);
-            const validatedData = scheduleRequestDTO.validate('bulk_delete'); // 'bulk_delete' 타입 검증
-
-            const { time_idxs } = validatedData;
-
-            const result = await ScheduleService.deleteSchedules(userId, time_idxs);
-
-            return res.status(200).json({
-                success: true,
-                data: {
-                    message: 'Schedules successfully deleted',
-                    deleted_time_idxs: result.deleted_time_idxs
-                }
+            return await performanceMonitor.measureAsync('deleteSchedules', async () => {
+                const userId = req.user.id;
+                const scheduleRequestDTO = new ScheduleRequestDTO(req.body);
+                const validatedData = scheduleRequestDTO.validate('bulk_delete');
+
+                const result = await ScheduleService.deleteSchedules(userId, validatedData.title);
+
+                return res.status(200).json({
+                    success: true,
+                    data: {
+                        message: 'Schedule successfully deleted',
+                        deletedCount: result.deletedCount
+                    }
+                });
             });
         } catch (error) {
             return res.status(404).json({
@@ -136,19 +130,20 @@ class scheduleController {
             });
         }
     }
-
     /**
      * 해당 사용자 전체 스케줄 조회
      * GET /api/schedule/all
      */
     async getAllSchedules(req, res) {
         try {
-            const userId = req.user.id;
-            const schedules = await ScheduleService.getAllSchedules(userId);
+            return await performanceMonitor.measureAsync('getAllSchedules', async () => {
+                const userId = req.user.id;
+                const schedules = await ScheduleService.getAllSchedules(userId);
 
-            return res.status(200).json({
-                success: true,
-                data: schedules
+                return res.status(200).json({
+                    success: true,
+                    data: { schedules }
+                });
             });
         } catch (error) {
             return res.status(500).json({
@@ -168,14 +163,18 @@ class scheduleController {
      */
     async getScheduleByTimeIdx(req, res) {
         try {
-            const { time_idx } = req.params;
-            const userId = req.user.id;
+            return await performanceMonitor.measureAsync('getScheduleByTimeIdx', async () => {
+                const { time_idx } = req.params;
+                const userId = req.user.id;
+                const scheduleRequestDTO = new ScheduleRequestDTO({ time_idx: parseInt(time_idx, 10) });
+                const validatedData = scheduleRequestDTO.validate('get_by_time_idx');
 
-            const schedule = await ScheduleService.getScheduleByTimeIdx(userId, parseInt(time_idx, 10));
+                const schedule = await ScheduleService.getScheduleByTimeIdx(userId, validatedData.time_idx);
 
-            return res.status(200).json({
-                success: true,
-                data: schedule
+                return res.status(200).json({
+                    success: true,
+                    data: { schedule }
+                });
             });
         } catch (error) {
             if (error.message === 'Schedule not found') {
diff --git a/dtos/ScheduleRequestDTO.js b/dtos/ScheduleRequestDTO.js
index 854bd3f124ebe293fe781924683ed0d9b0a4c168..218f9e040e224a1b7b00f144e510a26e640cb4e3 100644
--- a/dtos/ScheduleRequestDTO.js
+++ b/dtos/ScheduleRequestDTO.js
@@ -13,27 +13,28 @@ class ScheduleRequestDTO {
             schema = Joi.object({
                 title: Joi.string().min(1).max(255).required(),
                 is_fixed: Joi.boolean().required(),
-                events: Joi.array().items(
-                    Joi.object({
-                        time_idx: Joi.number().integer().min(0).max(671).required(),
-                    })
-                ).min(1).required()
+                time_indices: Joi.array()
+                    .items(Joi.number().integer().min(0).max(671))
+                    .min(1)
+                    .required()
             });
         } else if (type === 'bulk_update') {
             schema = Joi.object({
-                updates: Joi.array().items(
-                    Joi.object({
-                        time_idx: Joi.number().integer().min(0).max(671).required(),
-                        title: Joi.string().min(1).max(255).optional(),
-                        is_fixed: Joi.boolean().optional(),
-                    })
-                ).min(1).required()
+                originalTitle: Joi.string().min(1).max(255).required(),
+                title: Joi.string().min(1).max(255).required(),
+                is_fixed: Joi.boolean().required(),
+                time_indices: Joi.array()
+                    .items(Joi.number().integer().min(0).max(671))
+                    .min(1)
+                    .required()
             });
         } else if (type === 'bulk_delete') {
             schema = Joi.object({
-                time_idxs: Joi.array().items(
-                    Joi.number().integer().min(0).max(671).required()
-                ).min(1).required()
+                title: Joi.string().min(1).max(255).required()
+            });
+        } else if (type === 'get_by_time_idx') {
+            schema = Joi.object({
+                time_idx: Joi.number().integer().min(0).max(671).required()
             });
         }
 
diff --git a/dtos/ScheduleResponseDTO.js b/dtos/ScheduleResponseDTO.js
index a75316e65e13999800b70b4e23e9c40203dccee8..75276216f17143fd685160c0a47e72dd8b61608e 100644
--- a/dtos/ScheduleResponseDTO.js
+++ b/dtos/ScheduleResponseDTO.js
@@ -1,14 +1,25 @@
 // dtos/ScheduleResponseDTO.js
 
 class ScheduleResponseDTO {
-  constructor(schedule) {
-      this.id = schedule.id;
-      this.user_id = schedule.user_id;
-      this.title = schedule.title;
-      this.time_idx = schedule.time_idx; // 새로운 time_idx 필드 추가
-      this.is_fixed = schedule.is_fixed;
-      this.createdAt = schedule.createdAt;
-      this.updatedAt = schedule.updatedAt;
+  static groupSchedules(schedules) {
+      const grouped = schedules.reduce((acc, schedule) => {
+          const key = `${schedule.title}-${schedule.is_fixed}`;
+          if (!acc[key]) {
+              acc[key] = {
+                  id: schedule.id,
+                  user_id: schedule.user_id,
+                  title: schedule.title,
+                  is_fixed: schedule.is_fixed,
+                  time_indices: [],
+                  createdAt: schedule.createdAt,
+                  updatedAt: schedule.updatedAt
+              };
+          }
+          acc[key].time_indices.push(schedule.time_idx);
+          return acc;
+      }, {});
+
+      return Object.values(grouped);
   }
 }
 
diff --git a/middlewares/auth.js b/middlewares/auth.js
index afc74eaad5520ace4dbb2b36a9a644cec88e8387..52eb397476e16fa8c98e7d2e29a15973d76215bc 100644
--- a/middlewares/auth.js
+++ b/middlewares/auth.js
@@ -1,15 +1,16 @@
 // middlewares/auth.js
-
-exports.isLoggedIn = (req, res, next) => { //로그인된 사용자자만 접근허용
+exports.isLoggedIn = (req, res, next) => { // 로그인된 사용자만 접근 허용
   if (req.isAuthenticated()) {
     return next();
   }
-  res.redirect('/auth/login');
+  // 리다이렉트 대신 401 Unauthorized 상태 반환
+  res.status(401).json({ error: '로그인 되지않은 사용자' });
 };
 
-exports.isNotLoggedIn = (req, res, next) => { //로그인 안되면 리다이렉트 
+exports.isNotLoggedIn = (req, res, next) => { // 로그인 안된 사용자만 접근 허용
   if (!req.isAuthenticated()) {
     return next();
   }
-  res.redirect('/');
+  // 리다이렉트 대신 400 Bad Request 상태 반환 (필요에 따라 변경 가능)
+  res.status(400).json({ error: '이미 로그인된' });
 };
diff --git a/models/fcmToken.js b/models/fcmToken.js
index f9fa9207dcf3adaf53875e9c78fd040ee78f4eec..855b833ed49fe0de3b033f59676ce3fbe17c1077 100644
--- a/models/fcmToken.js
+++ b/models/fcmToken.js
@@ -1,3 +1,4 @@
+//models/friend.js
 const { DataTypes } = require('sequelize');
 const sequelize = require('../config/sequelize');
 const User = require('./user'); // 올바른 경로 확인
diff --git a/models/Friend.js b/models/friend.js
similarity index 100%
rename from models/Friend.js
rename to models/friend.js
diff --git a/models/index.js b/models/index.js
index 2998026a2b9ad6d4f59a58d48c0eca3b23229c43..7caa67277dc86e3f1dcc043a15e8897cbc7ee641 100644
--- a/models/index.js
+++ b/models/index.js
@@ -10,32 +10,106 @@ const Invite =require('./invite')
 const MeetingParticipant = require('./meetingParticipant');
 // const ChatRooms = require('./ChatRooms');
 
-// 관계 설정
-Friend.belongsTo(User, { foreignKey: 'requester_id', as: 'requester' }); // 친구 요청을 보낸 사용자
-Friend.belongsTo(User, { foreignKey: 'receiver_id', as: 'receiver' });   // 친구 요청을 받은 사용자
+// Friend 관계 설정
+Friend.belongsTo(User, {
+  foreignKey: 'requester_id',
+  as: 'requester',
+  onDelete: 'CASCADE',
+});
+Friend.belongsTo(User, {
+  foreignKey: 'receiver_id',
+  as: 'receiver',
+  onDelete: 'CASCADE',
+});
+User.hasMany(Friend, {
+  foreignKey: 'requester_id',
+  as: 'sentRequests',
+  onDelete: 'CASCADE',
+});
+User.hasMany(Friend, {
+  foreignKey: 'receiver_id',
+  as: 'receivedRequests',
+  onDelete: 'CASCADE',
+});
 
-User.hasMany(Friend, { foreignKey: 'requester_id', as: 'sentRequests' }); // 친구 요청을 보낸 목록
-User.hasMany(Friend, { foreignKey: 'receiver_id', as: 'receivedRequests' }); // 친구 요청을 받은 목록
-// 연관 관계 설정
-Meeting.belongsTo(User, { foreignKey: 'created_by', as: 'creator' });
-User.hasMany(Meeting, { foreignKey: 'created_by', as: 'meetings' });
+// Meeting 관계 설정
+Meeting.belongsTo(User, {
+  foreignKey: 'created_by',
+  as: 'creator',
+  onDelete: 'SET NULL', 
+});
+User.hasMany(Meeting, {
+  foreignKey: 'created_by',
+  as: 'meetings',
+  onDelete: 'SET NULL',
+});
 
-MeetingParticipant.belongsTo(Meeting, { foreignKey: 'meeting_id', as: 'meeting' });
-Meeting.hasMany(MeetingParticipant, { foreignKey: 'meeting_id', as: 'participants' });
+// MeetingParticipant 관계 설정
+MeetingParticipant.belongsTo(Meeting, {
+  foreignKey: 'meeting_id',
+  as: 'meeting',
+  onDelete: 'CASCADE',
+});
+Meeting.hasMany(MeetingParticipant, {
+  foreignKey: 'meeting_id',
+  as: 'participants',
+  onDelete: 'CASCADE',
+});
+MeetingParticipant.belongsTo(User, {
+  foreignKey: 'user_id',
+  as: 'user',
+  onDelete: 'CASCADE',
+});
+User.hasMany(MeetingParticipant, {
+  foreignKey: 'user_id',
+  as: 'meetingParticipations',
+  onDelete: 'CASCADE',
+});
 
-MeetingParticipant.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
-User.hasMany(MeetingParticipant, { foreignKey: 'user_id', as: 'meetingParticipations' });
+// Schedule 관계 설정
+Schedule.belongsTo(User, {
+  foreignKey: 'user_id',
+  as: 'user',
+  onDelete: 'CASCADE',
+});
+User.hasMany(Schedule, {
+  foreignKey: 'user_id',
+  as: 'schedules',
+  onDelete: 'CASCADE',
+});
 
-Schedule.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
-User.hasMany(Schedule, { foreignKey: 'user_id', as: 'schedules' });
+// Invite 관계 설정
+Invite.belongsTo(Meeting, {
+  foreignKey: 'meeting_id',
+  as: 'meeting',
+  onDelete: 'CASCADE',
+});
+Invite.belongsTo(User, {
+  foreignKey: 'inviter_id',
+  as: 'inviter',
+  onDelete: 'CASCADE',
+});
+Invite.belongsTo(User, {
+  foreignKey: 'invitee_id',
+  as: 'invitee',
+  onDelete: 'CASCADE',
+});
+User.hasMany(Invite, {
+  foreignKey: 'inviter_id',
+  as: 'sentInvites',
+  onDelete: 'CASCADE',
+});
+User.hasMany(Invite, {
+  foreignKey: 'invitee_id',
+  as: 'receivedInvites',
+  onDelete: 'CASCADE',
+});
+Meeting.hasMany(Invite, {
+  foreignKey: 'meeting_id',
+  as: 'invites',
+  onDelete: 'CASCADE',
+});
 
-Invite.belongsTo(Meeting, { foreignKey: 'meeting_id', as: 'meeting' });
-Invite.belongsTo(User, { foreignKey: 'inviter_id', as: 'inviter' }); // 초대한 사용자
-Invite.belongsTo(User, { foreignKey: 'invitee_id', as: 'invitee' }); // 초대받은 사용자
-
-User.hasMany(Invite, { foreignKey: 'inviter_id', as: 'sentInvites' }); // 보낸 초대 목록
-User.hasMany(Invite, { foreignKey: 'invitee_id', as: 'receivedInvites' }); // 받은 초대 목록
-Meeting.hasMany(Invite, { foreignKey: 'meeting_id', as: 'invites' }); // 해당 미팅의 모든 초대
 
 module.exports = {
     sequelize,
@@ -46,5 +120,4 @@ module.exports = {
     MeetingParticipant,
   Friend,
   FcmToken, 
-  Invite,
 };
diff --git a/models/Invite.js b/models/invite.js
similarity index 86%
rename from models/Invite.js
rename to models/invite.js
index d4e6105550ab73c611ed17055684c2358645a51c..621344c2d6d6994ea705737129b0e28752f3df35 100644
--- a/models/Invite.js
+++ b/models/invite.js
@@ -1,7 +1,8 @@
-//models/invite.js
-
+// models/invite.js
 const { DataTypes } = require('sequelize');
 const sequelize = require('../config/sequelize');
+const User = require('./user');
+const Meeting = require('./meeting');
 
 const Invite = sequelize.define('Invite', {
     status: {
diff --git a/output.log b/output.log
new file mode 100644
index 0000000000000000000000000000000000000000..f50856d2ff07cf69b2737346ecb7af37efe6c5b0
--- /dev/null
+++ b/output.log
@@ -0,0 +1,92 @@
+MongoDB URI: mongodb+srv://admin:lim1234!!@goodmeeting.vkniz.mongodb.net/
+(node:237546) [MONGODB DRIVER] Warning: useNewUrlParser is a deprecated option: useNewUrlParser has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version
+(Use `node --trace-warnings ...` to show where the warning was created)
+(node:237546) [MONGODB DRIVER] Warning: useUnifiedTopology is a deprecated option: useUnifiedTopology has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version
+✅ MongoDB 연결 성공
+Rdb데이터베이스 연결 성공.
+모든 모델이 성공적으로 동기화되었습니다.
+Server is running on 8080
+GET /api/session/info 401 9.962 ms - 76
+GET /api/chat/unread-messages/%EC%9E%84%EC%84%B8%ED%98%84 200 18.575 ms - 2
+GET /api/chat/rooms 304 71.212 ms - -
+GET /api/session/info 401 1.954 ms - 76
+GET /api/auth/login 302 3.293 ms - 0
+GET /api/auth/google/callback?code=4%2F0AeanS0bo56K9bp52E_K4k1_MsLy3ISx6PmunHrrE1MlEYKczIMg2thRYYgY7Fk-YzLgDLA&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid&authuser=1&hd=ajou.ac.kr&prompt=none 302 453.008 ms - 48
+GET /api/session/info 200 6.112 ms - 51
+GET /api/session/info 200 16.234 ms - 51
+GET /api/chat/unread-messages/%EC%9E%84%EC%84%B8%ED%98%84 304 22.679 ms - -
+GET /api/chat/rooms 304 23.630 ms - -
+GET /api/session/info 200 6.990 ms - 51
+GET /api/session/info 200 7.645 ms - 51
+GET /api/chat/rooms 304 16.225 ms - -
+GET /api/chat/unread-messages/%EC%9E%84%EC%84%B8%ED%98%84 304 11.814 ms - -
+GET /api/schedule/all 304 9.932 ms - -
+Performance Measurement - getAllSchedules: 5.537642002105713ms
+GET /api/session/info 200 7.587 ms - 51
+GET /api/chat/rooms 304 16.365 ms - -
+GET /api/chat/unread-messages/%EC%9E%84%EC%84%B8%ED%98%84 304 11.954 ms - -
+GET /api/schedule/all 304 19.858 ms - -
+Performance Measurement - getAllSchedules: 4.0661240220069885ms
+POST /api/schedule 201 57.019 ms - 254
+Performance Measurement - createSchedule: 32.22604298591614ms
+POST /api/schedule 201 18.985 ms - 209
+Performance Measurement - createSchedule: 14.478051960468292ms
+GET /api/session/info 401 1.989 ms - 76
+GET /api/session/info 200 18.484 ms - 51
+GET /api/meeting/my?page=0&size=20 200 27.169 ms - 73
+GET /api/friend/all?page=0&size=10 200 12.508 ms - 73
+Performance Measurement - getFriendList: 8.078101992607117ms
+GET /api/friend/requests/received 200 21.379 ms - 26
+Performance Measurement - getReceivedRequests: 12.82328200340271ms
+GET /api/session/info 200 5.489 ms - 51
+GET /api/session/info 200 8.371 ms - 51
+GET /api/meeting/my?page=0&size=20 304 16.133 ms - -
+GET /api/friend/all?page=0&size=10 304 29.121 ms - -
+Performance Measurement - getFriendList: 6.826422989368439ms
+GET /api/friend/requests/received 304 32.139 ms - -
+Performance Measurement - getReceivedRequests: 5.952132999897003ms
+GET /api/session/info 200 22.840 ms - 51
+GET /api/session/info 200 9.178 ms - 51
+GET /api/meeting/my?page=0&size=20 304 14.669 ms - -
+OPTIONS /api/schedule/all 204 0.464 ms - 0
+OPTIONS /api/schedule/all 204 0.141 ms - 0
+OPTIONS /api/schedule/all 204 0.210 ms - 0
+OPTIONS /api/schedule/all 204 0.142 ms - 0
+GET /api/session/info 401 0.925 ms - 76
+GET /api/session/info 401 1.223 ms - 76
+GET /api/chat/rooms 304 8.083 ms - -
+GET /api/chat/unread-messages/%EC%8B%AC%EC%9E%AC%EC%97%BD 304 4.635 ms - -
+GET /api/session/info 401 0.874 ms - 76
+GET /api/auth/login? 302 0.917 ms - 0
+GET /api/auth/google/callback?code=4%2F0AeanS0bOw-YtdxF3OtlXlNJwNPikLk99RTj2hA5DEUqDh90OVHztLhrKtkMXUSWpI-uqyQ&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid&authuser=0&hd=ajou.ac.kr&prompt=none 302 474.318 ms - 48
+GET /api/session/info 200 3.726 ms - 51
+GET /api/session/info 200 14.662 ms - 51
+GET /api/chat/rooms 304 21.626 ms - -
+GET /api/chat/unread-messages/%EC%8B%AC%EC%9E%AC%EC%97%BD 304 22.687 ms - -
+GET /api/session/info 200 6.551 ms - 51
+GET /api/meeting/my?page=0&size=20 304 8.614 ms - -
+GET /api/session/info 200 5.132 ms - 51
+GET /api/chat/rooms 304 13.220 ms - -
+GET /api/chat/unread-messages/%EC%8B%AC%EC%9E%AC%EC%97%BD 304 8.728 ms - -
+OPTIONS /api/schedule/all 204 0.184 ms - 0
+OPTIONS /api/schedule/all 204 0.134 ms - 0
+OPTIONS /api/schedule/all 204 0.192 ms - 0
+OPTIONS /api/schedule/all 204 0.235 ms - 0
+GET /api/friend/requests/received 304 52.485 ms - -
+Performance Measurement - getReceivedRequests: 6.246300995349884ms
+GET /api/friend/all?page=0&size=10 304 49.049 ms - -
+Performance Measurement - getFriendList: 4.844668984413147ms
+GET /api/session/info 200 3.957 ms - 51
+GET /api/session/info 200 5.007 ms - 51
+GET /api/meeting/my?page=0&size=20 304 7.817 ms - -
+OPTIONS /api/schedule/all 204 0.228 ms - 0
+OPTIONS /api/schedule/all 204 0.145 ms - 0
+OPTIONS /api/schedule/all 204 0.194 ms - 0
+OPTIONS /api/schedule/all 204 0.158 ms - 0
+OPTIONS /api/schedule/all 204 0.198 ms - 0
+OPTIONS /api/schedule/all 204 0.135 ms - 0
+GET /api/session/info 401 0.856 ms - 76
+GET /api/session/info 401 0.662 ms - 76
+OPTIONS /api/schedule/all 204 0.377 ms - 0
+OPTIONS /api/schedule/all 204 0.478 ms - 0
+OPTIONS /api/schedule/all 204 0.194 ms - 0
diff --git a/package-lock.json b/package-lock.json
index 606fda2ae8a59791cd06433516eb3868de7badc8..802c64f2397dd75331fc18d1b6245657d4a973bb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
       "dependencies": {
         "amqplib": "^0.10.5",
         "connect-flash": "^0.1.1",
+        "connect-mongo": "^5.1.0",
         "cookie-parser": "^1.4.7",
         "cors": "^2.8.5",
         "dotenv": "^16.4.5",
@@ -253,7 +254,7 @@
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz",
       "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-crypto/sha256-js": "^5.2.0",
@@ -269,7 +270,7 @@
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz",
       "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -282,7 +283,7 @@
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz",
       "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/is-array-buffer": "^2.2.0",
@@ -296,7 +297,7 @@
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
       "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/util-buffer-from": "^2.2.0",
@@ -310,7 +311,7 @@
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz",
       "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-crypto/util": "^5.2.0",
@@ -325,7 +326,7 @@
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz",
       "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -335,7 +336,7 @@
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz",
       "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "^3.222.0",
@@ -347,7 +348,7 @@
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz",
       "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -360,7 +361,7 @@
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz",
       "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/is-array-buffer": "^2.2.0",
@@ -374,7 +375,7 @@
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
       "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/util-buffer-from": "^2.2.0",
@@ -443,7 +444,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.693.0.tgz",
       "integrity": "sha512-WfycTcylmrSOnCN8x/xeIjHa4gIV4UhG85LWLZ3M4US8+HJQ8l4c4WUf+pUoTaSxN86vhbXlz0iRvA89nF854Q==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-crypto/sha256-browser": "5.2.0",
@@ -496,7 +497,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.693.0.tgz",
       "integrity": "sha512-QEynrBC26x6TG9ZMzApR/kZ3lmt4lEIs2D+cHuDxt6fDGzahBUsQFBwJqhizzsM97JJI5YvmJhmihoYjdSSaXA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-crypto/sha256-browser": "5.2.0",
@@ -546,7 +547,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.693.0.tgz",
       "integrity": "sha512-UEDbYlYtK/e86OOMyFR4zEPyenIxDzO2DRdz3fwVW7RzZ94wfmSwBh/8skzPTuY1G7sI064cjHW0b0QG01Sdtg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-crypto/sha256-browser": "5.2.0",
@@ -600,7 +601,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.693.0.tgz",
       "integrity": "sha512-4S2y7VEtvdnjJX4JPl4kDQlslxXEZFnC50/UXVUYSt/AMc5A/GgspFNA5FVz4E3Gwpfobbf23hR2NBF8AGvYoQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-crypto/sha256-browser": "5.2.0",
@@ -652,7 +653,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.693.0.tgz",
       "integrity": "sha512-v6Z/kWmLFqRLDPEwl9hJGhtTgIFHjZugSfF1Yqffdxf4n1AWgtHS7qSegakuMyN5pP4K2tvUD8qHJ+gGe2Bw2A==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "3.692.0",
@@ -675,7 +676,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.693.0.tgz",
       "integrity": "sha512-hlpV3tkOhpFl87aToH6Q6k7JBNNuARBPk+irPMtgE8ZqpYRP9tJ/RXftirzZ7CqSzc7NEWe/mnbJzRXw7DfgVQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/client-cognito-identity": "3.693.0",
@@ -692,7 +693,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.693.0.tgz",
       "integrity": "sha512-hMUZaRSF7+iBKZfBHNLihFs9zvpM1CB8MBOTnTp5NGCVkRYF3SB2LH+Kcippe0ats4qCyB1eEoyQX99rERp2iQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/core": "3.693.0",
@@ -709,7 +710,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.693.0.tgz",
       "integrity": "sha512-sL8MvwNJU7ZpD7/d2VVb3by1GknIJUxzTIgYtVkDVA/ojo+KRQSSHxcj0EWWXF5DTSh2Tm+LrEug3y1ZyKHsDA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/core": "3.693.0",
@@ -731,7 +732,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.693.0.tgz",
       "integrity": "sha512-kvaa4mXhCCOuW7UQnBhYqYfgWmwy7WSBSDClutwSLPZvgrhYj2l16SD2lN4IfYdxARYMJJ1lFYp3/jJG/9Yk4Q==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/core": "3.693.0",
@@ -758,7 +759,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.693.0.tgz",
       "integrity": "sha512-42WMsBjTNnjYxYuM3qD/Nq+8b7UdMopUq5OduMDxoM3mFTV6PXMMnfI4Z1TNnR4tYRvPXAnuNltF6xmjKbSJRA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/credential-provider-env": "3.693.0",
@@ -782,7 +783,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.693.0.tgz",
       "integrity": "sha512-cvxQkrTWHHjeHrPlj7EWXPnFSq8x7vMx+Zn1oTsMpCY445N9KuzjfJTkmNGwU2GT6rSZI9/0MM02aQvl5bBBTQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/core": "3.693.0",
@@ -800,7 +801,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.693.0.tgz",
       "integrity": "sha512-479UlJxY+BFjj3pJFYUNC0DCMrykuG7wBAXfsvZqQxKUa83DnH5Q1ID/N2hZLkxjGd4ZW0AC3lTOMxFelGzzpQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/client-sso": "3.693.0",
@@ -820,7 +821,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.693.0.tgz",
       "integrity": "sha512-8LB210Pr6VeCiSb2hIra+sAH4KUBLyGaN50axHtIgufVK8jbKIctTZcVY5TO9Se+1107TsruzeXS7VeqVdJfFA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/core": "3.693.0",
@@ -840,7 +841,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.693.0.tgz",
       "integrity": "sha512-0CCH8GuH1E41Kpq52NujErbUIRewDWLkdbYO8UJGybDbUQ8KC5JG1tP7K20tKYHmVgJGXDHo+XUIG7ogHD6/JA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/client-cognito-identity": "3.693.0",
@@ -869,7 +870,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.693.0.tgz",
       "integrity": "sha512-BCki6sAZ5jYwIN/t3ElCiwerHad69ipHwPsDCxJQyeiOnJ8HG+lEpnVIfrnI8A0fLQNSF3Gtx6ahfBpKiv1Oug==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "3.692.0",
@@ -885,7 +886,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.693.0.tgz",
       "integrity": "sha512-dXnXDPr+wIiJ1TLADACI1g9pkSB21KkMIko2u4CJ2JCBoxi5IqeTnVoa6YcC8GdFNVRl+PorZ3Zqfmf1EOTC6w==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "3.692.0",
@@ -900,7 +901,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.693.0.tgz",
       "integrity": "sha512-0LDmM+VxXp0u3rG0xQRWD/q6Ubi7G8I44tBPahevD5CaiDZTkmNTrVUf0VEJgVe0iCKBppACMBDkLB0/ETqkFw==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "3.692.0",
@@ -916,7 +917,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.693.0.tgz",
       "integrity": "sha512-/KUq/KEpFFbQmNmpp7SpAtFAdViquDfD2W0QcG07zYBfz9MwE2ig48ALynXm5sMpRmnG7sJXjdvPtTsSVPfkiw==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/core": "3.693.0",
@@ -935,7 +936,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.693.0.tgz",
       "integrity": "sha512-YLUkMsUY0GLW/nfwlZ69cy1u07EZRmsv8Z9m0qW317/EZaVx59hcvmcvb+W4bFqj5E8YImTjoGfE4cZ0F9mkyw==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "3.692.0",
@@ -953,7 +954,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.693.0.tgz",
       "integrity": "sha512-nDBTJMk1l/YmFULGfRbToOA2wjf+FkQT4dMgYCv+V9uSYsMzQj8A7Tha2dz9yv4vnQgYaEiErQ8d7HVyXcVEoA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "3.692.0",
@@ -973,7 +974,7 @@
       "version": "3.692.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.692.0.tgz",
       "integrity": "sha512-RpNvzD7zMEhiKgmlxGzyXaEcg2khvM7wd5sSHVapOcrde1awQSOMGI4zKBQ+wy5TnDfrm170ROz/ERLYtrjPZA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.0",
@@ -987,7 +988,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.693.0.tgz",
       "integrity": "sha512-eo4F6DRQ/kxS3gxJpLRv+aDNy76DxQJL5B3DPzpr9Vkq0ygVoi4GT5oIZLVaAVIJmi6k5qq9dLsYZfWLUxJJSg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "3.692.0",
@@ -1003,7 +1004,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.693.0.tgz",
       "integrity": "sha512-ttrag6haJLWABhLqtg1Uf+4LgHWIMOVSYL+VYZmAp2v4PUGOwWmWQH0Zk8RM7YuQcLfH/EoR72/Yxz6A4FKcuw==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -1016,7 +1017,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.693.0.tgz",
       "integrity": "sha512-6EUfuKOujtddy18OLJUaXfKBgs+UcbZ6N/3QV4iOkubCUdeM1maIqs++B9bhCbWeaeF5ORizJw5FTwnyNjE/mw==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/types": "3.692.0",
@@ -1029,7 +1030,7 @@
       "version": "3.693.0",
       "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.693.0.tgz",
       "integrity": "sha512-td0OVX8m5ZKiXtecIDuzY3Y3UZIzvxEr57Hp21NOwieqKCG2UeyQWWeGPv0FQaU7dpTkvFmVNI+tx9iB8V/Nhg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@aws-sdk/middleware-user-agent": "3.693.0",
@@ -3816,7 +3817,6 @@
       "version": "1.1.9",
       "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz",
       "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "sparse-bitfield": "^3.0.3"
@@ -5616,7 +5616,7 @@
       "version": "3.1.8",
       "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.8.tgz",
       "integrity": "sha512-+3DOBcUn5/rVjlxGvUPKc416SExarAQ+Qe0bqk30YSUjbepwpS7QN0cyKUSifvLJhdMZ0WPzPP5ymut0oonrpQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5630,7 +5630,7 @@
       "version": "3.0.12",
       "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.12.tgz",
       "integrity": "sha512-YAJP9UJFZRZ8N+UruTeq78zkdjUHmzsY62J4qKWZ4SXB4QXJ/+680EfXXgkYA2xj77ooMqtUY9m406zGNqwivQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/node-config-provider": "^3.1.11",
@@ -5647,7 +5647,7 @@
       "version": "2.5.3",
       "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.3.tgz",
       "integrity": "sha512-96uW8maifUSmehaeW7uydWn7wBc98NEeNI3zN8vqakGpyCQgzyJaA64Z4FCOUmAdCJkhppd/7SZ798Fo4Xx37g==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/middleware-serde": "^3.0.10",
@@ -5667,7 +5667,7 @@
       "version": "3.2.7",
       "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.7.tgz",
       "integrity": "sha512-cEfbau+rrWF8ylkmmVAObOmjbTIzKyUC5TkBL58SbLywD0RCBC4JAUKbmtSm2w5KUJNRPGgpGFMvE2FKnuNlWQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/node-config-provider": "^3.1.11",
@@ -5684,7 +5684,7 @@
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.1.tgz",
       "integrity": "sha512-bH7QW0+JdX0bPBadXt8GwMof/jz0H28I84hU1Uet9ISpzUqXqRQ3fEZJ+ANPOhzSEczYvANNl3uDQDYArSFDtA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/protocol-http": "^4.1.7",
@@ -5698,7 +5698,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.10.tgz",
       "integrity": "sha512-3zWGWCHI+FlJ5WJwx73Mw2llYR8aflVyZN5JhoqLxbdPZi6UyKSdCeXAWJw9ja22m6S6Tzz1KZ+kAaSwvydi0g==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5714,7 +5714,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.10.tgz",
       "integrity": "sha512-Lp2L65vFi+cj0vFMu2obpPW69DU+6O5g3086lmI4XcnRCG8PxvpWC7XyaVwJCxsZFzueHjXnrOH/E0pl0zikfA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5725,7 +5725,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz",
       "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -5760,7 +5760,7 @@
       "version": "3.0.12",
       "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.12.tgz",
       "integrity": "sha512-1mDEXqzM20yywaMDuf5o9ue8OkJ373lSPbaSjyEvkWdqELhFMyNNgKGWL/rCSf4KME8B+HlHKuR8u9kRj8HzEQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/protocol-http": "^4.1.7",
@@ -5775,7 +5775,7 @@
       "version": "3.2.3",
       "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.3.tgz",
       "integrity": "sha512-Hdl9296i/EMptaX7agrSzJZDiz5Y8XPUeBbctTmMtnCguGpqfU3jVsTUan0VLaOhsnquqWLL8Bl5HrlbVGT1og==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/core": "^2.5.3",
@@ -5795,7 +5795,7 @@
       "version": "3.0.27",
       "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.27.tgz",
       "integrity": "sha512-H3J/PjJpLL7Tt+fxDKiOD25sMc94YetlQhCnYeNmina2LZscAdu0ZEZPas/kwePHABaEtqp7hqa5S4UJgMs1Tg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/node-config-provider": "^3.1.11",
@@ -5816,7 +5816,7 @@
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
       "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
-      "dev": true,
+      "devOptional": true,
       "funding": [
         "https://github.com/sponsors/broofa",
         "https://github.com/sponsors/ctavan"
@@ -5830,7 +5830,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.10.tgz",
       "integrity": "sha512-MnAuhh+dD14F428ubSJuRnmRsfOpxSzvRhaGVTvd/lrUDE3kxzCCmH8lnVTvoNQnV2BbJ4c15QwZ3UdQBtFNZA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5844,7 +5844,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.10.tgz",
       "integrity": "sha512-grCHyoiARDBBGPyw2BeicpjgpsDFWZZxptbVKb3CRd/ZA15F/T6rZjCCuBUjJwdck1nwUuIxYtsS4H9DDpbP5w==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5858,7 +5858,7 @@
       "version": "3.1.11",
       "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.11.tgz",
       "integrity": "sha512-URq3gT3RpDikh/8MBJUB+QGZzfS7Bm6TQTqoh4CqE8NBuyPkWa5eUXj0XFcFfeZVgg3WMh1u19iaXn8FvvXxZw==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/property-provider": "^3.1.10",
@@ -5874,7 +5874,7 @@
       "version": "3.3.1",
       "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.1.tgz",
       "integrity": "sha512-fr+UAOMGWh6bn4YSEezBCpJn9Ukp9oR4D32sCjCo7U81evE11YePOQ58ogzyfgmjIO79YeOdfXXqr0jyhPQeMg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/abort-controller": "^3.1.8",
@@ -5891,7 +5891,7 @@
       "version": "3.1.10",
       "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.10.tgz",
       "integrity": "sha512-n1MJZGTorTH2DvyTVj+3wXnd4CzjJxyXeOgnTlgNVFxaaMeT4OteEp4QrzF8p9ee2yg42nvyVK6R/awLCakjeQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5905,7 +5905,7 @@
       "version": "4.1.7",
       "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.7.tgz",
       "integrity": "sha512-FP2LepWD0eJeOTm0SjssPcgqAlDFzOmRXqXmGhfIM52G7Lrox/pcpQf6RP4F21k0+O12zaqQt5fCDOeBtqY6Cg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5919,7 +5919,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.10.tgz",
       "integrity": "sha512-nT9CQF3EIJtIUepXQuBFb8dxJi3WVZS3XfuDksxSCSn+/CzZowRLdhDn+2acbBv8R6eaJqPupoI/aRFIImNVPQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5934,7 +5934,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.10.tgz",
       "integrity": "sha512-Oa0XDcpo9SmjhiDD9ua2UyM3uU01ZTuIrNdZvzwUTykW1PM8o2yJvMh1Do1rY5sUQg4NDV70dMi0JhDx4GyxuQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5948,7 +5948,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.10.tgz",
       "integrity": "sha512-zHe642KCqDxXLuhs6xmHVgRwy078RfqxP2wRDpIyiF8EmsWXptMwnMwbVa50lw+WOGNrYm9zbaEg0oDe3PTtvQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1"
@@ -5961,7 +5961,7 @@
       "version": "3.1.11",
       "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.11.tgz",
       "integrity": "sha512-AUdrIZHFtUgmfSN4Gq9nHu3IkHMa1YDcN+s061Nfm+6pQ0mJy85YQDB0tZBCmls0Vuj22pLwDPmL92+Hvfwwlg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -5975,7 +5975,7 @@
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.3.tgz",
       "integrity": "sha512-pPSQQ2v2vu9vc8iew7sszLd0O09I5TRc5zhY71KA+Ao0xYazIG+uLeHbTJfIWGO3BGVLiXjUr3EEeCcEQLjpWQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/is-array-buffer": "^3.0.0",
@@ -5995,7 +5995,7 @@
       "version": "3.4.4",
       "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.4.4.tgz",
       "integrity": "sha512-dPGoJuSZqvirBq+yROapBcHHvFjChoAQT8YPWJ820aPHHiowBlB3RL1Q4kPT1hx0qKgJuf+HhyzKi5Gbof4fNA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/core": "^2.5.3",
@@ -6014,7 +6014,7 @@
       "version": "3.7.1",
       "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.1.tgz",
       "integrity": "sha512-XKLcLXZY7sUQgvvWyeaL/qwNPp6V3dWcUjqrQKjSb+tzYiCy340R/c64LV5j+Tnb2GhmunEX0eou+L+m2hJNYA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -6027,7 +6027,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.10.tgz",
       "integrity": "sha512-j90NUalTSBR2NaZTuruEgavSdh8MLirf58LoGSk4AtQfyIymogIhgnGUU2Mga2bkMkpSoC9gxb74xBXL5afKAQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/querystring-parser": "^3.0.10",
@@ -6039,7 +6039,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz",
       "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/util-buffer-from": "^3.0.0",
@@ -6054,7 +6054,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz",
       "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -6064,7 +6064,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz",
       "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -6077,7 +6077,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz",
       "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/is-array-buffer": "^3.0.0",
@@ -6091,7 +6091,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz",
       "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -6104,7 +6104,7 @@
       "version": "3.0.27",
       "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.27.tgz",
       "integrity": "sha512-GV8NvPy1vAGp7u5iD/xNKUxCorE4nQzlyl057qRac+KwpH5zq8wVq6rE3lPPeuFLyQXofPN6JwxL1N9ojGapiQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/property-provider": "^3.1.10",
@@ -6121,7 +6121,7 @@
       "version": "3.0.27",
       "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.27.tgz",
       "integrity": "sha512-7+4wjWfZqZxZVJvDutO+i1GvL6bgOajEkop4FuR6wudFlqBiqwxw3HoH6M9NgeCd37km8ga8NPp2JacQEtAMPg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/config-resolver": "^3.0.12",
@@ -6140,7 +6140,7 @@
       "version": "2.1.6",
       "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.6.tgz",
       "integrity": "sha512-mFV1t3ndBh0yZOJgWxO9J/4cHZVn5UG1D8DeCc6/echfNkeEJWu9LD7mgGH5fHrEdR7LDoWw7PQO6QiGpHXhgA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/node-config-provider": "^3.1.11",
@@ -6155,7 +6155,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz",
       "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -6168,7 +6168,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.10.tgz",
       "integrity": "sha512-eJO+/+RsrG2RpmY68jZdwQtnfsxjmPxzMlQpnHKjFPwrYqvlcT+fHdT+ZVwcjlWSrByOhGr9Ff2GG17efc192A==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/types": "^3.7.1",
@@ -6182,7 +6182,7 @@
       "version": "3.0.10",
       "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.10.tgz",
       "integrity": "sha512-1l4qatFp4PiU6j7UsbasUHL2VU023NRB/gfaa1M0rDqVrRN4g3mCArLRyH3OuktApA4ye+yjWQHjdziunw2eWA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/service-error-classification": "^3.0.10",
@@ -6197,7 +6197,7 @@
       "version": "3.3.1",
       "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.1.tgz",
       "integrity": "sha512-Ff68R5lJh2zj+AUTvbAU/4yx+6QPRzg7+pI7M1FbtQHcRIp7xvguxVsQBKyB3fwiOwhAKu0lnNyYBaQfSW6TNw==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/fetch-http-handler": "^4.1.1",
@@ -6217,7 +6217,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz",
       "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "tslib": "^2.6.2"
@@ -6230,7 +6230,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz",
       "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==",
-      "dev": true,
+      "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@smithy/util-buffer-from": "^3.0.0",
@@ -7287,14 +7287,12 @@
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
       "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
-      "dev": true,
       "license": "MIT"
     },
     "node_modules/@types/whatwg-url": {
       "version": "11.0.5",
       "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
       "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "@types/webidl-conversions": "*"
@@ -8305,6 +8303,18 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/asn1.js": {
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+      "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+      "license": "MIT",
+      "dependencies": {
+        "bn.js": "^4.0.0",
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0",
+        "safer-buffer": "^2.1.0"
+      }
+    },
     "node_modules/ast-module-types": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-5.0.0.tgz",
@@ -8813,6 +8823,12 @@
       "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
       "license": "MIT"
     },
+    "node_modules/bn.js": {
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
+      "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
+      "license": "MIT"
+    },
     "node_modules/body-parser": {
       "version": "1.20.3",
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
@@ -8848,7 +8864,7 @@
       "version": "2.11.0",
       "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz",
       "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==",
-      "dev": true,
+      "devOptional": true,
       "license": "MIT"
     },
     "node_modules/brace-expansion": {
@@ -8927,7 +8943,6 @@
       "version": "6.9.0",
       "resolved": "https://registry.npmjs.org/bson/-/bson-6.9.0.tgz",
       "integrity": "sha512-X9hJeyeM0//Fus+0pc5dSUMhhrrmWwQUtdavaQeF3Ta6m69matZkGWV/MrBcnwUeLC8W9kwwc2hfkZgUuCX3Ig==",
-      "dev": true,
       "license": "Apache-2.0",
       "engines": {
         "node": ">=16.20.1"
@@ -9896,6 +9911,46 @@
         "node": ">= 0.4.0"
       }
     },
+    "node_modules/connect-mongo": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-5.1.0.tgz",
+      "integrity": "sha512-xT0vxQLqyqoUTxPLzlP9a/u+vir0zNkhiy9uAdHjSCcUUf7TS5b55Icw8lVyYFxfemP3Mf9gdwUOgeF3cxCAhw==",
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.3.1",
+        "kruptein": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=12.9.0"
+      },
+      "peerDependencies": {
+        "express-session": "^1.17.1",
+        "mongodb": ">= 5.1.0 < 7"
+      }
+    },
+    "node_modules/connect-mongo/node_modules/debug": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+      "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/connect-mongo/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "license": "MIT"
+    },
     "node_modules/console-control-strings": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
@@ -12050,7 +12105,6 @@
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz",
       "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==",
-      "dev": true,
       "license": "Apache-2.0",
       "optional": true,
       "peer": true,
@@ -12066,7 +12120,6 @@
       "version": "5.1.3",
       "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz",
       "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==",
-      "dev": true,
       "license": "Apache-2.0",
       "optional": true,
       "peer": true,
@@ -15677,6 +15730,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/kruptein": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.7.tgz",
+      "integrity": "sha512-vTftnEjfbqFHLqxDUMQCj6gBo5lKqjV4f0JsM8rk8rM3xmvFZ2eSy4YALdaye7E+cDKnEj7eAjFR3vwh8a4PgQ==",
+      "license": "MIT",
+      "dependencies": {
+        "asn1.js": "^5.4.1"
+      },
+      "engines": {
+        "node": ">8"
+      }
+    },
     "node_modules/lazystream": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
@@ -16090,7 +16155,6 @@
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
       "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
-      "dev": true,
       "license": "MIT"
     },
     "node_modules/merge-descriptors": {
@@ -16197,6 +16261,12 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/minimalistic-assert": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+      "license": "ISC"
+    },
     "node_modules/minimatch": {
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
@@ -16578,7 +16648,6 @@
       "version": "6.10.0",
       "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz",
       "integrity": "sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==",
-      "dev": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@mongodb-js/saslprep": "^1.1.5",
@@ -16625,7 +16694,6 @@
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz",
       "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==",
-      "dev": true,
       "license": "Apache-2.0",
       "dependencies": {
         "@types/whatwg-url": "^11.0.2",
@@ -18396,7 +18464,6 @@
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
       "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-      "dev": true,
       "license": "MIT",
       "engines": {
         "node": ">=6"
@@ -19625,7 +19692,6 @@
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
       "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "memory-pager": "^1.0.2"
@@ -21095,7 +21161,6 @@
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
       "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "punycode": "^2.3.0"
@@ -21680,7 +21745,6 @@
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
       "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
-      "dev": true,
       "license": "BSD-2-Clause",
       "engines": {
         "node": ">=12"
@@ -21749,7 +21813,6 @@
       "version": "13.0.0",
       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz",
       "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "tr46": "^4.1.1",
diff --git a/package.json b/package.json
index 8e51516724be5ca51ee4886fdc9f36b8634bf4ee..aa8c29f37efa405f247a7234f5d985aa7cc0dde9 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
   "dependencies": {
     "amqplib": "^0.10.5",
     "connect-flash": "^0.1.1",
+    "connect-mongo": "^5.1.0",
     "cookie-parser": "^1.4.7",
     "cors": "^2.8.5",
     "dotenv": "^16.4.5",
diff --git a/passport/googleStrategy.js b/passport/googleStrategy.js
index 7acaf173e06eef64c1bf1dc82b22b181154801c6..f6698b36fab68e39e1d5b078802a20e197594797 100644
--- a/passport/googleStrategy.js
+++ b/passport/googleStrategy.js
@@ -1,15 +1,15 @@
 // passport/googleStrategy.js
-
 const { Strategy: GoogleStrategy } = require('passport-google-oauth20');
-const User = require('../models/user');
+const User = require('../models/user'); 
 
 module.exports = new GoogleStrategy(
   {
-    clientID: process.env.GOOGLE_CLIENT_ID, // .env 파일에 설정
+    clientID: process.env.GOOGLE_CLIENT_ID,
     clientSecret: process.env.GOOGLE_CLIENT_SECRET,
     callbackURL: process.env.CALLBACK_URL,
+    passReqToCallback: true, // req 객체를 콜백에 전달
   },
-  async (accessToken, refreshToken, profile, done) => {
+  async (req, accessToken, refreshToken, profile, done) => {
     try {
       // 프로필에서 사용자 정보 추출
       const email = profile.emails[0].value;
@@ -23,7 +23,7 @@ module.exports = new GoogleStrategy(
 
       return done(null, user);
     } catch (err) {
-      return done(err);
+      return done(err, null);
     }
   }
 );
diff --git a/routes/auth.js b/routes/auth.js
deleted file mode 100644
index 7eda249d0f05a64d3537bc0462e2da4f7c6fd831..0000000000000000000000000000000000000000
--- a/routes/auth.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// routes/auth.js
-
-const express = require('express');
-const passport = require('passport');
-
-const router = express.Router();
-
-// GET /auth/login
-router.get('/login', (req, res) => {
-  res.send('<a href="/auth/google">Log in with Google</a>');
-});
-
-// GET /auth/logout
-router.get('/logout', (req, res) => {
-  req.logout(() => {
-    res.redirect('/');
-  });
-});
-
-// GET /auth/google
-router.get(
-  '/google',
-  passport.authenticate('google', { scope: ['profile', 'email'] })
-);
-
-// GET /auth/google/callback
-router.get(
-  '/google/callback',
-  passport.authenticate('google', { failureRedirect: '/auth/login' }),
-  (req, res) => {
-    res.redirect('/');
-  }
-);
-
-module.exports = router;
diff --git a/routes/authRoute.js b/routes/authRoute.js
new file mode 100644
index 0000000000000000000000000000000000000000..a83f6d484e2469e47eebbd4d6af82392b619c61f
--- /dev/null
+++ b/routes/authRoute.js
@@ -0,0 +1,109 @@
+const express = require('express');
+const passport = require('passport');
+const MemberService = require('../services/memberService');
+
+const router = express.Router();
+
+// Google OAuth 로그인 라우터
+router.get(
+  '/login',
+  (req, res, next) => {
+    const { state } = req.query; // 클라이언트에서 전달된 state(fcmToken)
+    console.log("State received at /login:", state);
+
+    passport.authenticate("google", {
+      scope: ["profile", "email"], // 요청할 사용자 정보
+      state, // 전달받은 fcmToken을 state로 설정
+    })(req, res, next);
+  }
+);
+
+router.get(
+  '/google/callback',
+  passport.authenticate('google', {
+    failureRedirect: `${process.env.FRONT_URL}/login`
+  }),
+  async (req, res) => {
+    // Google OAuth 인증 성공 후 state 파라미터로 전달된 fcmToken 가져오기
+    const fcmToken = req.query.state;
+    console.log("받아온 fcmToken", fcmToken);
+    const userEmail = req.user.email; // Google 로그인에서 가져온 email
+    const redirectUrl = process.env.FRONT_URL;
+    req.session.userEmail = userEmail; // 세션에 사용자 이메일 저장
+
+    try {
+      if (fcmToken) {
+        // FCM 토큰 등록
+        await MemberService.registerToken(userEmail, fcmToken);
+        console.log(`FCM token registered for user: ${userEmail}`);
+      } else {
+        console.warn("No FCM token provided during login");
+      }
+    } catch (error) {
+      console.error("Error registering FCM token during login:", error);
+    }
+
+    req.session.save((err) => {
+      if (err) {
+        console.error('세션 저장 오류:', err);
+        return res.status(500).json({ error: '서버 오류' });
+      }
+      res.redirect(redirectUrl);
+
+    });
+  }
+);
+
+// 로그아웃 라우터
+router.get('/logout', (req, res) => {
+  if (req.session) {
+    req.session.destroy((err) => {
+      if (err) {
+        console.error('세션 삭제 오류:', err);
+        return res.status(500).json({ error: '서버 오류' });
+      }
+      const redirectUrl = process.env.FRONT_URL;
+      res.redirect(redirectUrl);
+    });
+  } else {
+    // 세션이 없는 경우에도 리다이렉트
+    const redirectUrl = process.env.FRONT_URL;
+    res.redirect(redirectUrl);
+  }
+});
+
+// 사용자 삭제 라우터
+router.delete('/leave', async (req, res) => {
+  try {
+    // 인증된 사용자 확인
+    if (!req.user) {
+      return res.status(401).json({ error: '인증되지 않은 사용자입니다.' });
+    }
+
+    const userId = req.user.id;
+
+    // 사용자 삭제
+    const deleted = await User.destroy({
+      where: { id: userId }
+    });
+
+    if (!deleted) {
+      return res.status(404).json({ error: '사용자를 찾을 수 없습니다.' });
+    }
+
+    // 세션 삭제
+    req.session.destroy((err) => {
+      if (err) {
+        console.error('세션 삭제 오류:', err);
+        return res.status(500).json({ error: '서버 오류' });
+      }
+      // 성공 메시지 반환 (리다이렉트 대신 JSON 응답)
+      res.status(200).json({ message: '사용자 계정이 성공적으로 삭제되었습니다.' });
+    });
+  } catch (error) {
+    console.error('사용자 삭제 오류:', error);
+    res.status(500).json({ error: '서버 오류' });
+  }
+});
+
+module.exports = router;
\ No newline at end of file
diff --git a/routes/chatRoute.js b/routes/chatRoute.js
index 6ae03f13f5e429e9c245c289d859400f99ac799a..ed55aa560c36105aff3706f702bda26fe0c6f234 100644
--- a/routes/chatRoute.js
+++ b/routes/chatRoute.js
@@ -1,6 +1,7 @@
 const express = require('express');
 const router = express.Router();
 const chatController = require('../controllers/chatController');
+const { isLoggedIn } = require('../middlewares/auth');
 
 router.post('/create-room', chatController.createChatRoom);
 router.get('/rooms', chatController.getChatRooms);
@@ -11,4 +12,11 @@ router.get('/unread-count/:chatRoomId', chatController.getUnreadCount);
 router.post('/update-status-and-logid', chatController.updateStatusAndLogId);
 router.post('/update-read-log-id', chatController.updateReadLogId);
 
+router.use(isLoggedIn);
+
+router.post('/:chatRoomId/notices', chatController.addNotice); 
+router.get('/:chatRoomId/notices/latest', chatController.getLatestNotice); 
+router.get('/:chatRoomId/notices', chatController.getAllNotices);
+router.get('/:chatRoomId/notices/:noticeId', chatController.getNoticeById);
+
 module.exports = router;
diff --git a/routes/friend.js b/routes/friendRoute.js
similarity index 100%
rename from routes/friend.js
rename to routes/friendRoute.js
diff --git a/routes/inviteRoutes.js b/routes/inviteRoute.js
similarity index 100%
rename from routes/inviteRoutes.js
rename to routes/inviteRoute.js
diff --git a/routes/meetingRoute.js b/routes/meetingRoute.js
index a2788cad0c127f0b8014ffe20ccca7f86b061b9b..a85d20297d3f8b8f51fd5c11645ac829c9a3d680 100644
--- a/routes/meetingRoute.js
+++ b/routes/meetingRoute.js
@@ -7,6 +7,9 @@ const MeetingController = require('../controllers/meetingController');
 
 router.use(isLoggedIn);
 
+// 내가 참여한 모임 목록 조회
+router.get('/my', MeetingController.getMyMeetings);
+
 // 번개 모임 생성
 router.post('/', MeetingController.createMeeting);
 
@@ -22,4 +25,9 @@ router.post('/:meetingId/join', MeetingController.joinMeeting);
 // 번개 모임 상세 조회
 router.get('/:meetingId', MeetingController.getMeetingDetail);
 
+// 번개 모임 탈퇴
+router.delete('/:meetingId/leave', MeetingController.leaveMeeting);
+
+
+
 module.exports = router;
\ No newline at end of file
diff --git a/routes/performanceRoute.js b/routes/performanceRoute.js
new file mode 100644
index 0000000000000000000000000000000000000000..eeab98cf437121ab8bd3c8904bbc0683e36a8198
--- /dev/null
+++ b/routes/performanceRoute.js
@@ -0,0 +1,14 @@
+// routes/performanceRoute.js
+const express = require('express');
+const router = express.Router();
+const performanceMonitor = require('../utils/performanceMonitor');
+
+router.get('/stats', (req, res) => {
+    const stats = performanceMonitor.getAllStats();
+    res.json({
+        success: true,
+        data: { stats }
+    });
+});
+
+module.exports = router;
diff --git a/routes/schedule.js b/routes/scheduleRoute.js
similarity index 100%
rename from routes/schedule.js
rename to routes/scheduleRoute.js
diff --git a/routes/sessionRoute.js b/routes/sessionRoute.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ecd2922a17ef9e4f9fe9e1093090e98d7f4a082
--- /dev/null
+++ b/routes/sessionRoute.js
@@ -0,0 +1,23 @@
+const express = require('express');
+const router = express.Router();
+
+// GET /api/session/info
+router.get('/info', (req, res) => {
+  if (req.user) {
+    const { email, name } = req.user;
+  // 캐싱 비활성화
+    res.set('Cache-Control', 'no-store');
+    res.set('Pragma', 'no-cache');        
+    return res.status(200).json({
+      email,name
+    });
+  }
+  // 세션이 만료되었거나 사용자 정보가 없는 경우
+  res.set('Cache-Control', 'no-store');
+  res.set('Pragma', 'no-cache');
+  res.status(401).json({
+    message: '세션이 만료되었거나 사용자 정보가 없습니다.',
+  });
+});
+
+module.exports = router;
\ No newline at end of file
diff --git a/schemas/ChatRooms.js b/schemas/chatRooms.js
similarity index 85%
rename from schemas/ChatRooms.js
rename to schemas/chatRooms.js
index 1c2001cfe54dcc6c3034a23e01b3bc706100b94b..beaba10e774b5036b2206fc0a4152b5fc105f9a6 100644
--- a/schemas/ChatRooms.js
+++ b/schemas/chatRooms.js
@@ -1,7 +1,5 @@
-// schemas/chatRooms.js
 const mongoose = require('mongoose');
 
-// MongoDB 채팅방 스키마 수정 (FCM 토큰을 배열로 관리)
 const chatRoomsSchema = new mongoose.Schema({
   chatRoomId: { type: String, required: true, unique: true },
   chatRoomName: { type: String, required: true },
@@ -18,6 +16,11 @@ const chatRoomsSchema = new mongoose.Schema({
   lastReadAt: { type: Map, of: Date },
   lastReadLogId: { type: Map, of: String },
   isOnline: { type: Map, of: Boolean },
+  notices: [{ 
+    sender: { type: String },
+    message: { type: String },
+    timestamp: { type: Date, default: Date.now }, 
+  }]
 }, { collection: 'chatrooms' });
 
 const ChatRooms = mongoose.models.ChatRooms || mongoose.model('ChatRooms', chatRoomsSchema);
diff --git a/services/chatService.js b/services/chatService.js
index 0d462a5da57a7d0ce940cbafa7dbe7eee295828b..f67ee428d4efc761df9dd467600ec25eb93e4cbc 100644
--- a/services/chatService.js
+++ b/services/chatService.js
@@ -209,6 +209,87 @@ class ChatService {
     }
   }
 
+  // 공지사항 추가
+  async addNotice(chatRoomId, sender, message) {
+    try {
+      const newNotice = {
+        sender,
+        message,
+        timestamp: new Date(),
+      };
+
+      const updatedChatRoom = await ChatRooms.findOneAndUpdate(
+        { chatRoomId },
+        { $push: { notices: newNotice } }, // 공지사항 배열에 추가
+        { new: true }
+      );
+
+      if (!updatedChatRoom) {
+        throw new Error('Chat room not found');
+      }
+
+      return newNotice;
+    } catch (error) {
+      console.error('Error adding notice:', error.message);
+      throw new Error('Failed to add notice');
+    }
+  }
+
+  // 최신 공지사항 조회
+  async getLatestNotice(chatRoomId) {
+    try {
+      const chatRoom = await ChatRooms.findOne(
+        { chatRoomId },
+        { notices: { $slice: -1 } } // 최신 공지 1개만 가져오기
+      );
+
+      if (!chatRoom || chatRoom.notices.length === 0) {
+        return null;
+      }
+
+      return chatRoom.notices[0];
+    } catch (error) {
+      console.error('Error fetching latest notice:', error.message);
+      throw new Error('Failed to fetch latest notice');
+    }
+  }
+
+  // 공지사항 전체 조회
+  async getAllNotices(chatRoomId) {
+    try {
+      const chatRoom = await ChatRooms.findOne({ chatRoomId }, { notices: 1 });
+
+      if (!chatRoom) {
+        throw new Error('Chat room not found');
+      }
+
+      return chatRoom.notices;
+    } catch (error) {
+      console.error('Error fetching all notices:', error.message);
+      throw new Error('Failed to fetch all notices');
+    }
+  }
+
+  // 공지사항 상세 조회
+  async getNoticeById(chatRoomId, noticeId) {
+    try {
+      const chatRoom = await ChatRooms.findOne({ chatRoomId });
+      if (!chatRoom) {
+        throw new Error('Chat room not found');
+      }
+
+      const notice = chatRoom.notices.find(notice => notice._id.toString() === noticeId);
+      if (!notice) {
+        throw new Error('Notice not found');
+      }
+
+      return notice;
+    } catch (error) {
+      console.error('Error in getNoticeById:', error.message);
+      throw error;
+    }
+  }
+
 }
 
 module.exports = new ChatService();
\ No newline at end of file
diff --git a/services/friendService.js b/services/friendService.js
index d35b3c700c9b4b1a1b7a18326eafb2eace829478..5e1652459a2276272c5559d997137e238db0178e 100644
--- a/services/friendService.js
+++ b/services/friendService.js
@@ -11,9 +11,7 @@ const FriendListDTO = require('../dtos/FriendListDTO');
 class FriendService {
     /**
      * User 존재 여부 유효성 검사
-     * @param {number} userId - 검사할 사용자 ID
-     * @returns {Promise<User>} - 유효한 사용자 객체
-     * @throws {Error} - 사용자가 존재하지 않을 경우
+     * userId - 검사할 사용자 ID
      */
     async validUser(userId) {
         const user = await User.findByPk(userId);
@@ -25,10 +23,9 @@ class FriendService {
 
     /**
      * 친구 요청 보내기
-     * @param {number} userId - 친구 요청을 보내는 사용자 ID
-     * @param {number} friendId - 친구 요청을 받는 사용자 ID
-     * @returns {Promise<FriendResponseDTO>} - 생성된 친구 요청 DTO
-     * @throws {Error} - 유효하지 않은 요청일 경우
+     * userId - 친구 요청을 보내는 사용자 ID
+     * friendId - 친구 요청을 받는 사용자 ID
+     * returns - 생성된 친구 요청 DTO
      */
     async sendFriendRequest(userId, friendId) {
         await this.validUser(userId);
@@ -81,8 +78,8 @@ class FriendService {
 
     /**
      * 받은 친구 요청 목록 조회
-     * @param {number} userId - 요청을 받은 사용자 ID
-     * @returns {Promise<Array<FriendResponseDTO>>} - 받은 친구 요청 목록 DTO 배열
+      userId - 요청을 받은 사용자 ID
+     받은 친구 요청 목록 DTO 배열
      */
     async getReceivedRequests(userId) {
         const receivedRequests = await Friend.findAll({
@@ -101,8 +98,7 @@ class FriendService {
 
     /**
      * 보낸 친구 요청 목록 조회
-     * @param {number} userId - 요청을 보낸 사용자 ID
-     * @returns {Promise<Array<FriendResponseDTO>>} - 보낸 친구 요청 목록 DTO 배열
+     * userId - 요청을 보낸 사용자 ID
      */
     async getSentRequests(userId) {
         const sentRequests = await Friend.findAll({
@@ -163,10 +159,9 @@ class FriendService {
 
     /**
      * 친구 요청 거절
-     * @param {number} userId - 요청을 거절하는 사용자 ID
-     * @param {number} friendId - 친구 요청을 보낸 사용자 ID
-     * @returns {Promise<number>} - 삭제된 친구 요청 수
-     * @throws {Error} - 친구 요청이 존재하지 않을 경우
+     *userId - 요청을 거절하는 사용자 ID
+     *  friendId - 친구 요청을 보낸 사용자 ID
+     * returns  - 삭제된 친구 요청 수
      */
     async rejectFriendRequest(userId, friendId) {
         const result = await Friend.destroy({
@@ -186,10 +181,10 @@ class FriendService {
 
     /**
      * 친구 목록 조회
-     * @param {number} userId - 친구 목록을 조회할 사용자 ID
-     * @param {number} limit - 한 페이지에 표시할 친구 수
-     * @param {number} offset - 페이징 오프셋
-     * @returns {Promise<Array<FriendListDTO>>} - 친구 목록 DTO 배열
+     userId - 친구 목록을 조회할 사용자 ID
+     limit - 한 페이지에 표시할 친구 수
+     offset - 페이징 오프셋
+     친구 목록 DTO 배열
      */
     async getFriendList(userId, pagination) {
         const { limit = 20, offset = 0 } = pagination;
@@ -215,7 +210,7 @@ class FriendService {
                 }
             ],
             order: [['id', 'ASC']],
-            limit: limit + 1, // 다음 페이지 존재 여부 확인을 위해 1개 더 조회
+            limit: limit + 1, 
             offset
         });
     
@@ -232,10 +227,10 @@ class FriendService {
 
     /**
      * 친구 삭제
-     * @param {number} userId - 친구를 삭제하는 사용자 ID
-     * @param {number} friendId - 삭제할 친구의 사용자 ID
-     * @returns {Promise<number>} - 삭제된 친구 관계 수
-     * @throws {Error} - 친구 관계가 존재하지 않을 경우
+     - 친구를 삭제하는 사용자 ID
+     - 삭제할 친구의 사용자 ID
+     - 삭제된 친구 관계 수
+     -친구 관계가 존재하지 않을 경우
      */
     async deleteFriend(userId, friendId) {
         const result = await Friend.destroy({
diff --git a/services/meetingService.js b/services/meetingService.js
index 0c04014bb5f628591c57903f37a283c25b9f8217..bc7b7f784f9027f83f0ae5f777e50384c0a82e1d 100644
--- a/services/meetingService.js
+++ b/services/meetingService.js
@@ -1,7 +1,4 @@
 
-// const { Meeting, MeetingParticipant, User, Schedule } = require('../models');
-// const ChatRoom = require('../models/chatRooms');
-// const FcmToken = require('../models/fcmToken');
 // services/meetingService.js
 const { v4: uuidv4 } = require('uuid');
 const { Op } = require('sequelize');
@@ -121,20 +118,16 @@ class MeetingService {
                 { transaction }
             );
 
-            // 스케줄 생성 (모임 시간 범위 내 모든 time_idx에 대해 생성)
-            const events = [];
-            for (let idx = time_idx_start; idx <= time_idx_end; idx++) {
-                events.push({ time_idx: idx });
-            }
-            await ScheduleService.createSchedules(
-                {
-                    userId: created_by,
-                    title: `번개 모임: ${title}`,
-                    is_fixed: false,
-                    events: events,
-                },
-                transaction
+            const time_indices = Array.from(
+                { length: time_idx_end - time_idx_start + 1 },
+                (_, i) => time_idx_start + i
             );
+            await ScheduleService.createSchedules({
+                userId: created_by,
+                title: `번개 모임: ${title}`,
+                is_fixed: false,
+                time_indices: time_indices,
+            }, transaction);
 
             // 친구 초대 로직 호출
             const invitedFriendIds = await this.sendInvites({
@@ -267,24 +260,17 @@ class MeetingService {
             { transaction }
           );
 
-          // 스케줄 생성 (모임 시간 범위 내 모든 time_idx에 대해 생성)
-          const events = [];
-          for (
-            let idx = meeting.time_idx_start;
-            idx <= meeting.time_idx_end;
-            idx++
-          ) {
-            events.push({ time_idx: idx });
-          }
-          await ScheduleService.createSchedules(
-            {
-              userId: userId,
-              title: `번개 모임: ${meeting.title}`,
-              is_fixed: false,
-              events: events,
-            },
-            transaction
-          );
+        const time_indices = Array.from(
+            { length: meeting.time_idx_end - meeting.time_idx_start + 1 },
+            (_, i) => meeting.time_idx_start + i
+        );
+        
+        await ScheduleService.createSchedules({
+            userId: userId,
+            title: `번개 모임: ${meeting.title}`,
+            is_fixed: false,
+            time_indices: time_indices,
+        }, transaction);
 
           // 채팅방 참가 (MongoDB)
           const user = await User.findOne({
@@ -328,130 +314,111 @@ class MeetingService {
     
     async getMeetings(userId, pagination) {
         const { limit = 20, offset = 0 } = pagination;
-
-        const meetings = await Meeting.findAll({
-            attributes: [
-                'id',
-                'title',
-                'description',
-                'time_idx_start',
-                'time_idx_end',
-                'location',
-                'time_idx_deadline',
-                'type',
-                'max_num',
-                'cur_num',
-            ],
-            include: [
-                {
-                    model: MeetingParticipant,
-                    as: 'participants',
-                    required: false, 
-                    attributes: [],
-                },
-                {
-                    model: User,
-                    as: 'creator',
-                    attributes: ['name'],
-                }
-            ],
-            order: [['createdAt', 'DESC']],
-            offset
-        });
     
-        const hasNext = meetings.length > limit;
-        const content = await Promise.all(
-            meetings.slice(0, limit).map(async (meeting) => {
-                const isParticipant = await MeetingParticipant.findOne({
-                    where: {
-                        meeting_id: meeting.id,
-                        user_id: userId
+        try {
+            const meetings = await Meeting.findAll({
+                attributes: [
+                    'id', 'title', 'description',
+                    'time_idx_start', 'time_idx_end',
+                    'location', 'time_idx_deadline',
+                    'type', 'max_num', 'cur_num',
+                    'created_at'
+                ],
+                include: [
+                    {
+                        model: User,
+                        as: 'creator',
+                        attributes: ['name'],
+                        required: false
                     }
-                });
+                ],
+                order: [['created_at', 'DESC']],
+                limit: limit + 1,
+                offset,
+                distinct: true
+            });
     
-                const hasConflict = await ScheduleService.checkScheduleOverlapByTime(
-                    userId,
-                    meeting.time_idx_start,
-                    meeting.time_idx_end
-                );
+            const hasNext = meetings.length > limit;
+            const content = await Promise.all(
+                meetings.slice(0, limit).map(async (meeting) => {
+                    const isParticipant = await MeetingParticipant.findOne({
+                        where: {
+                            meeting_id: meeting.id,
+                            user_id: userId
+                        }
+                    });
     
-                const creatorName = meeting.creator ? meeting.creator.name : 'Unknown';
-                return new MeetingResponseDTO(meeting, !!isParticipant, hasConflict, creatorName);
-            })
-        );
+                    const hasConflict = await ScheduleService.checkScheduleOverlapByTime(
+                        userId,
+                        meeting.time_idx_start,
+                        meeting.time_idx_end
+                    );
     
-        return {
-            content,
-            hasNext
-        };
+                    return new MeetingResponseDTO(
+                        meeting,
+                        !!isParticipant,
+                        hasConflict,
+                        meeting.creator?.name || 'Unknown'
+                    );
+                })
+            );
+    
+            return { content, hasNext };
+        } catch (error) {
+            console.error('getMeetings error:', error);
+            throw new Error('Failed to fetch meetings');
+        }
     }
 
     async getMyMeetings(userId, pagination) {
         const { limit = 20, offset = 0 } = pagination;
     
-        const meetings = await Meeting.findAll({
-            attributes: [
-                'id',
-                'title',
-                'description',
-                'time_idx_start',
-                'time_idx_end',
-                'location',
-                'time_idx_deadline',
-                'type',
-                'max_num',
-                'cur_num',
-            ],
-            include: [
-                {
-                    model: MeetingParticipant,
-                    as: 'participants',
-                    where: { user_id: userId }, 
-                    attributes: [],
-                },
-                {
-                    model: User,
-                    as: 'creator',
-                    attributes: ['name'],
-                }
-            ],
-            where: {
-                [Op.or]: [
-                    { created_by: userId },  
-                    { '$participants.user_id$': userId }  
-                ]
-            },
-            order: [['createdAt', 'DESC']],
-            offset
-        });
-    
-        const hasNext = meetings.length > limit;
-        const content = await Promise.all(
-            meetings.slice(0, limit).map(async (meeting) => {
-                const isParticipant = await MeetingParticipant.findOne({
-                    where: {
-                        meeting_id: meeting.id,
-                        user_id: userId
+        try {
+            const meetings = await Meeting.findAll({
+                attributes: [
+                    'id', 'title', 'description',
+                    'time_idx_start', 'time_idx_end',
+                    'location', 'time_idx_deadline',
+                    'type', 'max_num', 'cur_num',
+                    'created_at'
+                ],
+                include: [
+                    {
+                        model: MeetingParticipant,
+                        as: 'participants',
+                        where: { user_id: userId },
+                        required: true
+                    },
+                    {
+                        model: User,
+                        as: 'creator',
+                        attributes: ['name'],
+                        required: false
                     }
-                });
+                ],
+                order: [['created_at', 'DESC']],
+                limit: limit + 1,
+                offset,
+                distinct: true
+            });
     
-                const hasConflict = await ScheduleService.checkScheduleOverlapByTime(
-                    userId,
-                    meeting.time_idx_start,
-                    meeting.time_idx_end
+            const hasNext = meetings.length > limit;
+            const content = meetings.slice(0, limit).map(meeting => {
+                return new MeetingResponseDTO(
+                    meeting,
+                    true,  // 참여자로 조회했으므로 항상 true
+                    false, // 이미 참여 중인 미팅이므로 충돌 체크 불필요
+                    meeting.creator?.name || 'Unknown'
                 );
+            });
     
-                const creatorName = meeting.creator ? meeting.creator.name : 'Unknown';
-                return new MeetingResponseDTO(meeting, !!isParticipant, hasConflict, creatorName);
-            })
-        );
-    
-        return {
-            content,
-            hasNext
-        };
+            return { content, hasNext };
+        } catch (error) {
+            console.error('getMyMeetings error:', error);
+            throw new Error('Failed to fetch my meetings');
+        }
     }
-
+    
     async getMeetingDetail(meetingId, userId) {
         const meeting = await Meeting.findByPk(meetingId, {
             include: [
@@ -612,7 +579,10 @@ class MeetingService {
             });
             if (chatRoom) {
                 const user = await User.findByPk(userId);
-                chatRoom.participants = chatRoom.participants.filter(p => p !== user.name);
+                chatRoom.participants = chatRoom.participants.filter(p => p.name !== user.name);
+                chatRoom.isOnline.delete(user.name);
+                chatRoom.lastReadAt.delete(user.name);
+                chatRoom.lastReadLogId.delete(user.name);
                 await chatRoom.save();
             }
     
diff --git a/services/memberService.js b/services/memberService.js
index 0435672d90a949dd46dcb7bad1de73d7fe764f69..ebe4fe15d7974bcfce53ad99dbc732ed79672bc2 100644
--- a/services/memberService.js
+++ b/services/memberService.js
@@ -25,7 +25,7 @@ class MemberService {
     }
 
     // 3. MongoDB에서 관련 채팅방의 FCM 토큰 업데이트
-    const existingChatRooms = await ChatRoom.find({ "participants.name": user.name });
+    const existingChatRooms = await ChatRooms.find({ "participants.name": user.name });
     for (const room of existingChatRooms) {
       room.participants = room.participants.map((participant) => {
         if (participant.name === user.name) {
diff --git a/services/modifyScheduleResponse.test.js b/services/modifyScheduleResponse.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..64ab78c260c61a9274df0f3f77fa5d459cc65934
--- /dev/null
+++ b/services/modifyScheduleResponse.test.js
@@ -0,0 +1,187 @@
+// test/scheduleService.test.js
+const sequelize = require('../config/sequelize');
+const { Schedule, User, Meeting, MeetingParticipant, FcmToken } = require('../models');
+const ScheduleService = require('../services/scheduleService');
+const MeetingService = require('../services/meetingService');
+const ChatRooms = require('../schemas/chatRooms');
+
+describe('Schedule Service and Meeting Integration Tests', () => {
+    beforeAll(async () => {
+        await sequelize.sync({ force: true });
+    });
+
+    beforeEach(async () => {
+        await MeetingParticipant.destroy({ where: {} });
+        await Meeting.destroy({ where: {} });
+        await Schedule.destroy({ where: {} });
+        await User.destroy({ where: {} });
+        await FcmToken.destroy({ where: {} });
+
+        // 더미 사용자 생성
+        await User.bulkCreate([
+            { id: 1, name: 'Alice', email: 'alice@example.com' },
+            { id: 2, name: 'Bob', email: 'bob@example.com' },
+            { id: 3, name: 'Charlie', email: 'charlie@example.com' }
+        ]);
+
+        // ChatRooms Mock 설정
+        jest.spyOn(ChatRooms.prototype, 'save').mockResolvedValue(undefined);
+        jest.spyOn(ChatRooms, 'findOne').mockResolvedValue({
+            participants: [],
+            isOnline: new Map(),
+            lastReadAt: new Map(),
+            lastReadLogId: new Map(),
+            save: jest.fn().mockResolvedValue(true)
+        });
+    });
+
+    afterAll(async () => {
+        await sequelize.close();
+    });
+
+    describe('Schedule Service Tests', () => {
+        test('should create schedule with time_indices', async () => {
+            const scheduleData = {
+                userId: 1,
+                title: 'Test Schedule',
+                is_fixed: true,
+                time_indices: [36, 37, 38]
+            };
+
+            const schedule = await ScheduleService.createSchedules(scheduleData);
+
+            expect(schedule).toBeDefined();
+            expect(schedule.title).toBe('Test Schedule');
+            expect(schedule.time_indices).toEqual([36, 37, 38]);
+
+            const dbSchedules = await Schedule.findAll({
+                where: { user_id: 1, title: 'Test Schedule' }
+            });
+            expect(dbSchedules.length).toBe(3);
+        });
+
+        test('should update schedule with new time_indices', async () => {
+            await ScheduleService.createSchedules({
+                userId: 1,
+                title: 'Original Schedule',
+                is_fixed: true,
+                time_indices: [36, 37, 38]
+            });
+
+            const updateData = {
+                originalTitle: 'Original Schedule',
+                title: 'Updated Schedule',
+                is_fixed: true,
+                time_indices: [36, 37, 38, 39]
+            };
+
+            const updatedSchedule = await ScheduleService.updateSchedules(1, updateData);
+
+            expect(updatedSchedule.title).toBe('Updated Schedule');
+            expect(updatedSchedule.time_indices).toEqual([36, 37, 38, 39]);
+        });
+
+        test('should delete schedule by title', async () => {
+            await ScheduleService.createSchedules({
+                userId: 1,
+                title: 'Schedule to Delete',
+                is_fixed: true,
+                time_indices: [40, 41, 42]
+            });
+
+            const result = await ScheduleService.deleteSchedules(1, 'Schedule to Delete');
+            expect(result.deletedCount).toBe(3);
+
+            const remainingSchedules = await Schedule.findAll({
+                where: { user_id: 1, title: 'Schedule to Delete' }
+            });
+            expect(remainingSchedules.length).toBe(0);
+        });
+    });
+
+    describe('Meeting Integration Tests', () => {
+        beforeEach(() => {
+            jest.spyOn(User, 'findOne').mockResolvedValue({
+                id: 1,
+                name: 'Alice',
+                email: 'alice@example.com',
+                fcmTokenList: []
+            });
+        });
+
+        test('should create meeting with correct schedules', async () => {
+            const meetingData = {
+                title: 'Test Meeting',
+                time_idx_start: 50,
+                time_idx_end: 52,
+                created_by: 1,
+                type: 'OPEN',
+                max_num: 5
+            };
+
+            const meeting = await MeetingService.createMeeting(meetingData);
+
+            const creatorSchedules = await Schedule.findAll({
+                where: {
+                    user_id: 1,
+                    title: `번개 모임: ${meetingData.title}`
+                }
+            });
+
+            expect(creatorSchedules.length).toBe(3);
+            expect(creatorSchedules.map(s => s.time_idx).sort()).toEqual([50, 51, 52]);
+        });
+
+        test('should create correct schedules when joining meeting', async () => {
+            const meetingData = {
+                title: 'Join Test Meeting',
+                time_idx_start: 60,
+                time_idx_end: 62,
+                created_by: 1,
+                type: 'OPEN',
+                max_num: 5,
+                time_idx_deadline: 59 
+            };
+
+            const meeting = await MeetingService.createMeeting(meetingData);
+            jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(58);
+
+            await MeetingService.joinMeeting(meeting.meeting_id, 2);
+
+            const participantSchedules = await Schedule.findAll({
+                where: {
+                    user_id: 2,
+                    title: `번개 모임: ${meetingData.title}`
+                }
+            });
+
+            expect(participantSchedules.length).toBe(3);
+            expect(participantSchedules.map(s => s.time_idx).sort()).toEqual([60, 61, 62]);
+        });
+
+        test('should handle schedule conflicts correctly', async () => {
+            await ScheduleService.createSchedules({
+                userId: 2,
+                title: 'Existing Schedule',
+                is_fixed: true,
+                time_indices: [70, 71]
+            });
+
+            const meetingData = {
+                title: 'Conflict Test Meeting',
+                time_idx_start: 70,
+                time_idx_end: 72,
+                created_by: 1,
+                type: 'OPEN',
+                max_num: 5,
+                time_idx_deadline: 69 
+            };
+
+            const meeting = await MeetingService.createMeeting(meetingData);
+
+            await expect(
+                MeetingService.joinMeeting(meeting.meeting_id, 2)
+            ).rejects.toThrow('스케줄이 겹칩니다');
+        });
+    });
+});
\ No newline at end of file
diff --git a/services/performance.test.js b/services/performance.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..e987e86bb2471becaa10ec51713bdc6a1d4c88d2
--- /dev/null
+++ b/services/performance.test.js
@@ -0,0 +1,203 @@
+// services/performance.test.js
+require('dotenv').config();
+const { Op } = require('sequelize');
+const ScheduleService = require('./scheduleService');
+const sequelize = require('../config/sequelize');
+const Schedule = require('../models/schedule');
+
+class PerformanceTester {
+    constructor() {
+        this.testUserIds = [1, 2, 3, 4, 5];  // 5명의 테스트 유저만 사용
+        this.results = {
+            operations: {
+                createSchedules: [],
+                getAllSchedules: [],
+                updateSchedules: [],
+                deleteSchedules: []
+            },
+            summary: {}
+        };
+    }
+
+    async setup() {
+        try {
+            await sequelize.authenticate();
+            console.log('Database connection established successfully.');
+            await Schedule.destroy({ where: {}, force: true });
+            console.log('Test data cleaned successfully.');
+            console.log('Using existing user IDs:', this.testUserIds);
+        } catch (error) {
+            console.error('Setup failed:', error);
+            throw error;
+        }
+    }
+
+    async runLoadTest() {
+        console.log('Starting simplified test...');
+
+        const testSchedules = this.testUserIds.map((userId, i) => ({
+            userId,
+            title: `Test Schedule ${i}`,
+            is_fixed: true,
+            time_indices: [i * 2, i * 2 + 1]
+        }));
+
+        console.log('Test schedules:', testSchedules);
+
+        const transaction = await sequelize.transaction();
+        try {
+            // Create 테스트
+            console.log('\nTesting createSchedules...');
+            const createdSchedules = [];
+            for (const schedule of testSchedules) {
+                const result = await this.measureOperation('createSchedules', async () => {
+                    const created = await ScheduleService.createSchedules(schedule, transaction);
+                    console.log(`Created schedule for user ${schedule.userId}`);
+                    return created;
+                });
+                if (result) createdSchedules.push(result);
+            }
+            await transaction.commit();
+
+            // 생성된 스케줄 확인
+            const verifySchedules = await Schedule.findAll({
+                where: {
+                    user_id: { [Op.in]: this.testUserIds }
+                },
+                raw: true
+            });
+            console.log('\nVerified schedules:', verifySchedules);
+
+            // GetAll 테스트
+            console.log('\nTesting getAllSchedules...');
+            for (const userId of this.testUserIds) {
+                await this.measureOperation('getAllSchedules', async () => {
+                    return await ScheduleService.getAllSchedules(userId);
+                });
+            }
+
+            // Update 테스트
+            console.log('\nTesting updateSchedules...');
+            for (const schedule of createdSchedules) {
+                await this.measureOperation('updateSchedules', async () => {
+                    return await ScheduleService.updateSchedules(schedule.user_id, {
+                        originalTitle: schedule.title,
+                        title: `Updated ${schedule.title}`,
+                        is_fixed: schedule.is_fixed,
+                        time_indices: schedule.time_indices
+                    });
+                });
+            }
+
+            // Delete 테스트
+            console.log('\nTesting deleteSchedules...');
+            const deleteTransaction = await sequelize.transaction();
+            try {
+                for (const schedule of createdSchedules) {
+                    await this.measureOperation('deleteSchedules', async () => {
+                        return await ScheduleService.deleteSchedules(
+                            schedule.user_id,
+                            `Updated ${schedule.title}`,
+                            deleteTransaction
+                        );
+                    });
+                }
+                await deleteTransaction.commit();
+            } catch (error) {
+                await deleteTransaction.rollback();
+                throw error;
+            }
+        } catch (error) {
+            await transaction.rollback();
+            throw error;
+        }
+
+        this.analyzePerfResults();
+    }
+
+    async measureOperation(name, operation) {
+        const start = process.hrtime.bigint();
+        try {
+            const result = await operation();
+            const end = process.hrtime.bigint();
+            const duration = Number(end - start) / 1000000;
+            this.results.operations[name].push({ success: true, duration });
+            return result;
+        } catch (error) {
+            const end = process.hrtime.bigint();
+            const duration = Number(end - start) / 1000000;
+            this.results.operations[name].push({
+                success: false,
+                duration,
+                error: error.message
+            });
+            console.error(`Error in ${name}:`, error.message);
+            return null;
+        }
+    }
+
+    analyzePerfResults() {
+        Object.entries(this.results.operations).forEach(([operation, results]) => {
+            const successful = results.filter(r => r.success);
+            const failed = results.filter(r => !r.success);
+            if (successful.length > 0) {
+                const durations = successful.map(r => r.duration);
+                this.results.summary[operation] = {
+                    totalRequests: results.length,
+                    successCount: successful.length,
+                    failCount: failed.length,
+                    avgDuration: durations.reduce((a, b) => a + b, 0) / successful.length,
+                    minDuration: Math.min(...durations),
+                    maxDuration: Math.max(...durations),
+                    p95: this.calculatePercentile(durations, 95),
+                    p99: this.calculatePercentile(durations, 99)
+                };
+            }
+        });
+        this.printResults();
+    }
+
+    calculatePercentile(array, percentile) {
+        const sorted = array.sort((a, b) => a - b);
+        const index = Math.ceil((percentile / 100) * sorted.length) - 1;
+        return sorted[index];
+    }
+
+    printResults() {
+        console.log('\n=== Performance Test Results ===');
+        Object.entries(this.results.summary).forEach(([operation, stats]) => {
+            console.log(`\n${operation}:`);
+            console.log(`Total Requests: ${stats.totalRequests}`);
+            console.log(`Success Rate: ${((stats.successCount / stats.totalRequests) * 100).toFixed(2)}%`);
+            console.log(`Average Duration: ${stats.avgDuration.toFixed(2)}ms`);
+            console.log(`Min Duration: ${stats.minDuration.toFixed(2)}ms`);
+            console.log(`Max Duration: ${stats.maxDuration.toFixed(2)}ms`);
+            console.log(`95th Percentile: ${stats.p95.toFixed(2)}ms`);
+            console.log(`99th Percentile: ${stats.p99.toFixed(2)}ms`);
+        });
+    }
+
+    async cleanup() {
+        try {
+            await Schedule.destroy({ where: {}, force: true });
+            console.log('Cleanup completed successfully.');
+        } catch (error) {
+            console.error('Cleanup failed:', error);
+        }
+    }
+}
+
+async function runTests() {
+    const tester = new PerformanceTester();
+    try {
+        await tester.setup();
+        console.log('Starting performance tests...');
+        await tester.runLoadTest();
+    } catch (error) {
+        console.error('Test failed:', error);
+    } finally {
+        await sequelize.close();
+    }
+}
+
+runTests();
\ No newline at end of file
diff --git a/services/schedule.test.js b/services/schedule.test.js
index 373d1e5b67bb78e5e043483ed798a012bbb1f114..1002f0acca632b902c9e6384d6f0f66c00b92fab 100644
--- a/services/schedule.test.js
+++ b/services/schedule.test.js
@@ -1,16 +1,14 @@
 // test/scheduleService.test.js
-const sequelize = require('../config/sequelize'); // 실제 경로에 맞게 수정
+const sequelize = require('../config/sequelize'); 
 const { Schedule, User } = require('../models');
-const ScheduleService = require('../services/scheduleService'); // Uppercase 'S'로 가져오기
+const ScheduleService = require('../services/scheduleService'); 
 const ScheduleResponseDTO = require('../dtos/ScheduleResponseDTO');
 
 beforeAll(async () => {
-    // 테스트 스위트가 시작되기 전에 데이터베이스를 동기화합니다.
     await sequelize.sync({ force: true });
 });
 
 beforeEach(async () => {
-    // 각 테스트가 시작되기 전에 기존 데이터를 삭제합니다.
     await Schedule.destroy({ where: {} });
     await User.destroy({ where: {} });
 
diff --git a/services/scheduleService.js b/services/scheduleService.js
index e664a4909abfbca48cbb533bcbcf67f77152382d..6c66d7ff0398f922ddec76baccc00c2d89fb2a40 100644
--- a/services/scheduleService.js
+++ b/services/scheduleService.js
@@ -9,158 +9,248 @@ class ScheduleService {
      * 스케줄 생성 (벌크)
      * @param {object} [transaction] - Sequelize 트랜잭션 객체 -> 미팅방에서 쓰기위해 트랜잭션을 넘겨받는걸 추가 
      */
-    async createSchedules({ userId, title, is_fixed, events }, transaction = null) {
-        const scheduleDTOs = [];
+    async createSchedules({ userId, title, is_fixed, time_indices }, transaction = null) {
+        const overlaps = await Schedule.findAll({
+            where: {
+                user_id: userId,
+                time_idx: {
+                    [Op.in]: time_indices
+                }
+            },
+            transaction
+        });
+
+        if (overlaps.length > 0) {
+            throw new Error(`Schedule overlaps at time_idx ${overlaps[0].time_idx}`);
+        }
 
-        for (const event of events) {
-            const { time_idx } = event;
+        const scheduleData = time_indices.map(time_idx => ({
+            user_id: userId,
+            title,
+            time_idx,
+            is_fixed
+        }));
 
-            // 중복 스케줄 검사
-            const overlap = await this.checkScheduleOverlap(userId, time_idx, transaction);
-            if (overlap) {
-                throw new Error(`Schedule overlaps with existing schedule at time_idx ${time_idx}`);
-            }
+        try {
+            const createdSchedules = await Schedule.bulkCreate(scheduleData, {
+                transaction,
+                returning: true,
+                validate: true
+            });
 
-            const scheduleData = {
+            return {
+                id: createdSchedules[0].id,
                 user_id: userId,
                 title,
-                time_idx,
                 is_fixed,
+                time_indices,
+                createdAt: createdSchedules[0].createdAt,
+                updatedAt: createdSchedules[0].updatedAt
             };
-
-            const schedule = await Schedule.create(scheduleData, { transaction });
-            scheduleDTOs.push(new ScheduleResponseDTO(schedule));
+        } catch (error) {
+            throw new Error(`Failed to bulk create schedules: ${error.message}`);
         }
+    }
+
+    async getAllSchedules(userId) {
+        try {
+            const schedules = await Schedule.findAll({
+                where: { user_id: userId },
+                order: [['time_idx', 'ASC']]
+            });
 
-        return scheduleDTOs;
+            return ScheduleResponseDTO.groupSchedules(schedules);
+        } catch (error) {
+            throw new Error(`Failed to fetch schedules: ${error.message}`);
+        }
     }
 
-    /**
-     * 스케줄 수정 (벌크)
-     * @param {Array} updates - 수정할 스케줄 배열
-     */
     async updateSchedules(userId, updates, transaction = null) {
-        const updatedSchedules = [];
-
-        for (const update of updates) {
-            const { time_idx, title, is_fixed } = update;
+        const { originalTitle, title, is_fixed, time_indices } = updates;
+        const t = transaction || await sequelize.transaction();
 
-            const schedule = await Schedule.findOne({
-                where: { user_id: userId, time_idx },
-                transaction,
-            });
+        try {
+            // 기존 스케줄 조회
+            const [existingSchedule, existingSchedules] = await Promise.all([
+                Schedule.findOne({
+                    where: {
+                        user_id: userId,
+                        title: originalTitle
+                    },
+                    transaction: t
+                }),
+                Schedule.findAll({
+                    attributes: ['time_idx'],
+                    where: {
+                        user_id: userId,
+                        title: originalTitle
+                    },
+                    transaction: t
+                })
+            ]);
 
-            if (!schedule) {
-                throw new Error(`Schedule not found at time_idx ${time_idx}`);
+            if (!existingSchedule) {
+                throw new Error('Schedule not found');
             }
 
-            const updatedData = {};
-            if (title !== undefined) updatedData.title = title;
-            if (is_fixed !== undefined) updatedData.is_fixed = is_fixed;
+            const existingTimeIndices = existingSchedules.map(s => s.time_idx);
+            const toDelete = existingTimeIndices.filter(idx => !time_indices.includes(idx));
+            const toAdd = time_indices.filter(idx => !existingTimeIndices.includes(idx));
 
-            const updatedSchedule = await schedule.update(updatedData, { transaction });
-            updatedSchedules.push(new ScheduleResponseDTO(updatedSchedule));
-        }
+            // 벌크 연산
+            const operations = [];
 
-        return updatedSchedules;
-    }
+            // 삭제 연산
+            if (toDelete.length > 0) {
+                operations.push(
+                    Schedule.destroy({
+                        where: {
+                            user_id: userId,
+                            title: originalTitle,
+                            time_idx: {
+                                [Op.in]: toDelete
+                            }
+                        },
+                        transaction: t
+                    })
+                );
+            }
 
-    /**
-     * 스케줄 삭제 (벌크)
-     * @param {number} userId - 사용자 ID
-     * @param {Array<number>} time_idxs - 삭제할 스케줄의 time_idx 배열
-     * @param {object} [transaction] - Sequelize 트랜잭션 객체
-     */
-    async deleteSchedules(userId, time_idxs, transaction = null) {
-        const deleted_time_idxs = [];
+            // 업데이트 연산
+            operations.push(
+                Schedule.update(
+                    { title, is_fixed },
+                    {
+                        where: {
+                            user_id: userId,
+                            title: originalTitle
+                        },
+                        transaction: t
+                    }
+                )
+            );
 
-        for (const time_idx of time_idxs) {
-            const deletedCount = await Schedule.destroy({
-                where: { user_id: userId, time_idx },
-                transaction,
-            });
+            // 생성 연산
+            if (toAdd.length > 0) {
+                operations.push(
+                    Schedule.bulkCreate(
+                        toAdd.map(time_idx => ({
+                            user_id: userId,
+                            title,
+                            time_idx,
+                            is_fixed
+                        })),
+                        {
+                            transaction: t,
+                            validate: true
+                        }
+                    )
+                );
+            }
 
-            if (deletedCount === 0) {
-                throw new Error(`Schedule not found at time_idx ${time_idx}`);
+            await Promise.all(operations); // 병렬 처리
+
+            if (!transaction) {
+                await t.commit();
             }
 
-            deleted_time_idxs.push(time_idx);
+            return {
+                id: existingSchedule.id,
+                user_id: userId,
+                title,
+                is_fixed,
+                time_indices,
+                createdAt: existingSchedule.createdAt,
+                updatedAt: new Date()
+            };
+
+        } catch (error) {
+            if (!transaction) {
+                await t.rollback();
+            }
+            throw error;
         }
+    }
+
+    async deleteSchedules(userId, title, transaction = null) {
+        const deletedSchedules = await Schedule.destroy({
+            where: {
+                user_id: userId,
+                title
+            },
+            transaction
+        });
 
-        return { deleted_time_idxs };
+        return { deletedCount: deletedSchedules };
     }
 
     /**
      * 특정 time_idx로 스케줄 조회
      */
     async getScheduleByTimeIdx(userId, time_idx) {
-        const schedule = await Schedule.findOne({
-            where: { user_id: userId, time_idx },
+        // 해당 time_idx의 스케줄 찾기
+        const schedules = await Schedule.findAll({
+            where: {
+                user_id: userId,
+                title: {
+                    [Op.in]: sequelize.literal(
+                        `(SELECT title FROM Schedules WHERE user_id = ${userId} AND time_idx = ${time_idx})`
+                    )
+                }
+            },
+            order: [['time_idx', 'ASC']]
         });
 
-        if (!schedule) {
-            throw new Error('Schedule not found');
-        }
-
-        return new ScheduleResponseDTO(schedule);
+        return ScheduleResponseDTO.groupSchedules(schedules)[0];
     }
 
-    /**
-     * 모든 스케줄 조회
-     */
     async getAllSchedules(userId) {
         try {
             const schedules = await Schedule.findAll({
                 where: { user_id: userId },
-                order: [['time_idx', 'ASC']],
+                order: [['time_idx', 'ASC']]
             });
-            return schedules.map((schedule) => new ScheduleResponseDTO(schedule));
+            return ScheduleResponseDTO.groupSchedules(schedules);
         } catch (error) {
             throw new Error(`Failed to fetch schedules: ${error.message}`);
         }
     }
 
-    /**
-     * 중복 스케줄 검사
-     */
     async checkScheduleOverlap(userId, time_idx, transaction = null) {
         const overlappingSchedule = await Schedule.findOne({
             where: { user_id: userId, time_idx },
-            transaction,
+            transaction
         });
-
         return !!overlappingSchedule;
     }
 
     async checkScheduleOverlapByTime(userId, time_idx_start, time_idx_end, transaction = null) {
-        console.log(
-            `checkScheduleOverlapByTime 호출: userId=${userId}, time_idx_start=${time_idx_start}, time_idx_end=${time_idx_end}`
-        );
-        const overlappingSchedule = await Schedule.findOne({
+        const overlappingSchedules = await Schedule.findAll({
             where: {
                 user_id: userId,
                 time_idx: {
-                    [Op.between]: [time_idx_start, time_idx_end] 
+                    [Op.between]: [time_idx_start, time_idx_end]
                 }
             },
-            transaction,
+            transaction
         });
-         console.log(`중복 스케줄: ${JSON.stringify(overlappingSchedule)}`);
-    const result = !!overlappingSchedule;
-    console.log(`스케줄 충돌 결과: ${result}`);
-    return result;
+
+        const groupedSchedules = ScheduleResponseDTO.groupSchedules(overlappingSchedules);
+        const result = groupedSchedules.length > 0;
+
+        console.log(`checkScheduleOverlapByTime 호출: userId=${userId}, time_idx_start=${time_idx_start}, time_idx_end=${time_idx_end}`);
+        console.log(`중복 스케줄: ${JSON.stringify(groupedSchedules)}`);
+        console.log(`스케줄 충돌 결과: ${result}`);
+
+        return result;
     }
-    
 
-    /**
-     * 만료된 스케줄 삭제
-     */
     async cleanExpiredSchedules() {
         try {
             const deletedCount = await Schedule.destroy({
-                where: { is_fixed: false },
+                where: { is_fixed: false }
             });
-            //console.log(`Deleted ${deletedCount} flexible schedules.`);
+            return { deletedCount };
         } catch (error) {
             console.error('Failed to clean expired schedules:', error);
             throw error;
diff --git a/start.sh b/start.sh
new file mode 100755
index 0000000000000000000000000000000000000000..00e9bb6ef347484cfd135e68776c215f20ef9957
--- /dev/null
+++ b/start.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# Define application file names
+APP_JS="app.js"
+WS_SERVER_JS="wsServer.js"
+
+# Find and kill processes for app.js
+APP_PID=$(pgrep -f "node .*${APP_JS}")
+if [ -n "$APP_PID" ]; then
+  echo "Stopping ${APP_JS} with PID: $APP_PID"
+  kill -9 "$APP_PID"
+else
+  echo "No running process found for ${APP_JS}"
+fi
+
+# Find and kill processes for wsServer.js
+WS_SERVER_PID=$(pgrep -f "node .*${WS_SERVER_JS}")
+if [ -n "$WS_SERVER_PID" ]; then
+  echo "Stopping ${WS_SERVER_JS} with PID: $WS_SERVER_PID"
+  kill -9 "$WS_SERVER_PID"
+else
+  echo "No running process found for ${WS_SERVER_JS}"
+fi
+
+# Start app.js with nohup
+echo "Starting ${APP_JS}..."
+nohup node "${APP_JS}" > output.log 2>&1 &
+echo "${APP_JS} started with PID: $!"
+
+# Start wsServer.js with nohup
+echo "Starting ${WS_SERVER_JS}..."
+nohup node "${WS_SERVER_JS}" > weblog.log 2>&1 &
+echo "${WS_SERVER_JS} started with PID: $!"
+
diff --git a/sync.js b/sync.js
index 84cfdef99fa993f2ee41affb5ea24f99dbb36aa7..3890bf2b4eb0b96a4d61b840044ded103e2623a5 100644
--- a/sync.js
+++ b/sync.js
@@ -1,7 +1,5 @@
 // sync.js
 
-//require('dotenv').config(); // 환경 변수 로드
-
 const sequelize = require('./config/sequelize');
 const model=require('./models'); // 모델들을 가져옴 (사이드 이펙트로 모델들이 등록됨)
 
diff --git a/utils/performanceMonitor.js b/utils/performanceMonitor.js
new file mode 100644
index 0000000000000000000000000000000000000000..dfba98533a396a4eaa540ef297c68b21526bdc51
--- /dev/null
+++ b/utils/performanceMonitor.js
@@ -0,0 +1,63 @@
+// utils/performanceMonitor.js
+const { performance, PerformanceObserver } = require('perf_hooks');
+
+class PerformanceMonitor {
+    constructor() {
+        this.measurements = new Map();
+        
+        // 성능 관찰자 설정
+        this.observer = new PerformanceObserver((items) => {
+            items.getEntries().forEach((entry) => {
+                const measurements = this.measurements.get(entry.name) || [];
+                measurements.push(entry.duration);
+                this.measurements.set(entry.name, measurements);
+                
+                console.log(`Performance Measurement - ${entry.name}: ${entry.duration}ms`);
+            });
+        });
+        
+        this.observer.observe({ entryTypes: ['measure'] });
+    }
+
+    async measureAsync(name, fn) {
+        const start = performance.now();
+        try {
+            return await fn();
+        } finally {
+            const duration = performance.now() - start;
+            performance.measure(name, { 
+                start,
+                duration,
+                detail: { timestamp: new Date().toISOString() }
+            });
+        }
+    }
+
+    getStats(name) {
+        const measurements = this.measurements.get(name) || [];
+        if (measurements.length === 0) return null;
+
+        const sum = measurements.reduce((a, b) => a + b, 0);
+        const avg = sum / measurements.length;
+        const min = Math.min(...measurements);
+        const max = Math.max(...measurements);
+
+        return {
+            count: measurements.length,
+            average: avg,
+            min: min,
+            max: max,
+            total: sum
+        };
+    }
+
+    getAllStats() {
+        const stats = {};
+        for (const [name, measurements] of this.measurements.entries()) {
+            stats[name] = this.getStats(name);
+        }
+        return stats;
+    }
+}
+
+module.exports = new PerformanceMonitor();
\ No newline at end of file
diff --git a/weblog.log b/weblog.log
new file mode 100644
index 0000000000000000000000000000000000000000..dbd9d956fe0863cb20caf8eb3c2078cd7e57aeb7
--- /dev/null
+++ b/weblog.log
@@ -0,0 +1,6 @@
+(node:237547) [MONGODB DRIVER] Warning: useNewUrlParser is a deprecated option: useNewUrlParser has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version
+(Use `node --trace-warnings ...` to show where the warning was created)
+(node:237547) [MONGODB DRIVER] Warning: useUnifiedTopology is a deprecated option: useUnifiedTopology has no effect since Node.js Driver version 4.0.0 and will be removed in the next major version
+MongoDB에 성공적으로 연결되었습니다.
+WebSocket 채팅 서버가 8081 포트에서 실행 중입니다.
+RabbitMQ connection established
diff --git a/wsServer.js b/wsServer.js
index e938ef812029c5d1147f6fc9aca204c69e7dc599..79e7b6d6550cd9baa4269da37be15fe8ea754f1a 100644
--- a/wsServer.js
+++ b/wsServer.js
@@ -10,22 +10,21 @@ const ChatRoom = require('./schemas/chatRooms');
 // .env 파일 로드
 dotenv.config();
 
-// 서비스 계정 키 파일 경로를 환경 변수에서 가져오기
-const serviceAccountPath = process.env.FIREBASE_CREDENTIAL_PATH;
+const HEARTBEAT_TIMEOUT = 10000; // 10초 후 타임아웃
 
-// Firebase Admin SDK 초기화
-admin.initializeApp({
-  credential: admin.credential.cert(require(serviceAccountPath)),
-});
+// RabbitMQ 연결 풀 생성
+let amqpConnection, amqpChannel;
 
 // WebSocket 관련 데이터
 let clients = [];
-let chatRooms = {};
+
+// 클라이언트 상태를 저장하는 Map
+const clientHeartbeats = new Map();
 
 // MongoDB 연결 설정
 async function connectMongoDB() {
   try {
-    await mongoose.connect('mongodb://localhost:27017/chat', {
+    await mongoose.connect(process.env.MONGO_URI, {
       useNewUrlParser: true,
       useUnifiedTopology: true,
     });
@@ -39,14 +38,35 @@ async function connectMongoDB() {
   }
 }
 
-// RabbitMQ 메시지 발행 함수
+// // RabbitMQ 메시지 발행 함수
+// async function publishToQueue(queue, message) {
+//   const connection = await amqp.connect(process.env.RABBITMQ_URL || 'amqp://localhost');
+//   const channel = await connection.createChannel();
+//   await channel.assertQueue(queue, { durable: true });
+//   channel.sendToQueue(queue, Buffer.from(JSON.stringify(message)));
+//   console.log(`Message sent to queue ${queue}:`, message);
+//   setTimeout(() => connection.close(), 500); // 연결 닫기
+// }
+
+async function setupRabbitMQ() {
+  try {
+    amqpConnection = await amqp.connect(process.env.RABBITMQ_URL || 'amqp://localhost');
+    amqpChannel = await amqpConnection.createChannel();
+    console.log('RabbitMQ connection established');
+  } catch (err) {
+    console.error('RabbitMQ Setup', err);
+    process.exit(1);
+  }
+}
+
 async function publishToQueue(queue, message) {
-  const connection = await amqp.connect(process.env.RABBITMQ_URL || 'amqp://localhost');
-  const channel = await connection.createChannel();
-  await channel.assertQueue(queue, { durable: true });
-  channel.sendToQueue(queue, Buffer.from(JSON.stringify(message)));
-  console.log(`Message sent to queue ${queue}:`, message);
-  setTimeout(() => connection.close(), 500); // 연결 닫기
+  try {
+    await amqpChannel.assertQueue(queue, { durable: true });
+    amqpChannel.sendToQueue(queue, Buffer.from(JSON.stringify(message)));
+    console.log(`Message sent to queue ${queue}:`, message);
+  } catch (err) {
+    logError('RabbitMQ Publish', err);
+  }
 }
 
 // RabbitMQ를 통해 푸시 알림 요청을 전송하는 함수
@@ -67,237 +87,355 @@ async function getChatHistory(chatRoomId) {
   return chatRoom ? chatRoom.messages : [];
 }
 
-// WebSocket 서버 생성 및 핸드셰이크 처리
 function startWebSocketServer() {
-  const wsServer = http.createServer((req, res) => {
+  const server = http.createServer((req, res) => {
     res.writeHead(200, { 'Content-Type': 'text/plain' });
     res.end('WebSocket server is running');
   });
 
-  wsServer.on('upgrade', (req, socket, head) => {
-    const key = req.headers['sec-websocket-key'];
-    const acceptKey = generateAcceptValue(key);
-    const responseHeaders = [
-      'HTTP/1.1 101 Switching Protocols',
-      'Upgrade: websocket',
-      'Connection: Upgrade',
-      `Sec-WebSocket-Accept: ${acceptKey}`
-    ];
-    socket.write(responseHeaders.join('\r\n') + '\r\n\r\n');
-
-    // 클라이언트를 clients 배열에 추가
-    clients.push(socket);
-
-    let chatRoomId = null;
-    let nickname = null;
-
-    socket.on('data', async buffer => {
-      let message;
-      try {
-        message = parseMessage(buffer);
-        const parsedData = JSON.parse(message);
-        const { type, chatRoomId: clientChatRoomId, nickname: clientNickname, text } = parsedData;
-
-        console.log('서버에서 수신한 메시지:', { type, clientChatRoomId, clientNickname, text });
-
-        if (type === 'join' || type === 'leave') {
-          await ChatRoom.updateOne(
-            { chatRoomId: clientChatRoomId },
-            { $set: { [`isOnline.${clientNickname}`]: type === 'join' } }
-          );
-
-          const statusMessage = {
-            type: 'status',
-            chatRoomId: clientChatRoomId,
-            nickname: clientNickname,
-            isOnline: type === 'join',
-          };
-
-          clients.forEach(client => {
-            client.write(constructReply(JSON.stringify(statusMessage)));
-          });
-        }
-
-        if (type === 'join') {
-          chatRoomId = clientChatRoomId;
-          nickname = clientNickname;
-
-          await ChatRoom.updateOne(
-            { chatRoomId },
-            {
-              $set: {
-                [`isOnline.${nickname}`]: true,
-                [`lastReadLogId.${nickname}`]: null,
-              },
-            }
-          );
-
-          if (!chatRooms[chatRoomId]) {
-            chatRooms[chatRoomId] = [];
-          }
-
-          const chatRoom = await ChatRoom.findOne({ chatRoomId });
-
-          // 참가자 확인
-          const participantIndex = chatRoom.participants.findIndex(participant => participant.name === nickname);
-          if (participantIndex !== -1) {
-            const existingParticipant = chatRoom.participants[participantIndex];
-
-            // 참가자 상태 업데이트
-            existingParticipant.isOnline = true;
-            existingParticipant.lastReadAt = new Date();
-
-            await chatRoom.save();
-          } else {
-            // 새 참가자 추가
-            const joinMessage = {
-              message: `${nickname}님이 참가했습니다.`,
-              timestamp: new Date(),
-              type: 'join'
-            };
-
-            chatRoom.participants.push({
-              name: nickname,
-              fcmTokens: parsedData.fcmToken ? [parsedData.fcmToken] : [],
-              lastReadAt: new Date(),
-              lastReadLogId: null,
-              isOnline: true,
-            });
-
-            chatRoom.messages.push(joinMessage);
-
-            await chatRoom.save();
-
-            clients.forEach(client => {
-              client.write(constructReply(JSON.stringify(joinMessage)));
-            });
-
-            console.log(`${nickname} 새 참가자로 추가`);
-          }
-
-          try {
-            const previousMessages = await getChatHistory(chatRoomId);
-            if (previousMessages.length > 0) {
-              socket.write(constructReply(JSON.stringify({ type: 'previousMessages', messages: previousMessages })));
-              console.log(`이전 메시지 전송: ${previousMessages.length}개`);
-            } 
-          } catch (err) {
-            console.error('이전 채팅 기록 불러오기 중 오류 발생:', err);
-          }
-
-        } else if (type === 'message') {
-          const chatMessage = {
-            message: text,
-            timestamp: new Date(),
-            type: 'message',
-            sender: nickname
-          };
-
-
-          chatRooms[chatRoomId].push(chatMessage);
-
-          try {
-            // 새로운 메시지를 messages 배열에 추가
-            const updatedChatRoom = await ChatRoom.findOneAndUpdate(
-              { chatRoomId }, 
-              { $push: { messages: chatMessage } },
-              { new: true, fields: { "messages": { $slice: -1 } } }  // 마지막 추가된 메시지만 가져옴
-            );
-
-            // 마지막에 추가된 메시지의 _id를 가져오기
-            const savedMessage = updatedChatRoom.messages[updatedChatRoom.messages.length - 1];
-
-            // 새로운 메시지 전송: 클라이언트로 메시지 브로드캐스트
-            const messageData = {
-              type: 'message',
-              chatRoomId,
-              sender: nickname,
-              message: text,
-              timestamp: chatMessage.timestamp,
-              _id: savedMessage._id  // 저장된 메시지의 _id 사용
-            };
-
-            clients.forEach(client => {
-              client.write(constructReply(JSON.stringify(messageData)));
-              console.log('채팅 메시지 전송:', messageData);
-            });
-
-            // 오프라인 사용자에게 FCM 푸시 알림 전송
-            const chatRoom = await ChatRoom.findOne({ chatRoomId });
-            const offlineParticipants = chatRoom.participants.filter(participant => {
-            // isOnline 상태를 Map에서 가져오기
-            const isOnline = chatRoom.isOnline.get(participant.name);
-              return isOnline === false; // 정확히 false인 사용자만 필터링
-            });
-
-            console.log("offlineParticipants", offlineParticipants);
-
-            // RabbitMQ에 푸시 알림 요청 발행
-            await sendPushNotificationRequest(chatRoom.chatRoomName, clientNickname, text, offlineParticipants, chatRoomId);
-          } catch (err) {
-            console.error('MongoDB 채팅 메시지 저장 오류:', err);
-          }
-        } else if (type === 'leave') {
-          const leaveMessage = { 
-            message: `${nickname}님이 퇴장했습니다.`, 
-            timestamp: new Date(),
-            type: 'leave'
-          };
-          
-          chatRooms[chatRoomId].push(leaveMessage);
-
-          await ChatRoom.updateOne(
-            { chatRoomId },
-            { $set: { [`isOnline.${nickname}`]: false } }
-          );
-
-          await ChatRoom.updateOne({ chatRoomId }, {
-            $push: { messages: leaveMessage },
-            $pull: { participants: nickname }
-          });
-
-          clients.forEach(client => {
-            client.write(constructReply(JSON.stringify(leaveMessage)));
-          });
-
-          clients = clients.filter(client => client !== socket);
-        }
-      } catch (err) {
-        console.error('메시지 처리 중 오류 발생:', err);
-      }
-    });
+  server.on('upgrade', (req, socket, head) => {
+    handleWebSocketUpgrade(req, socket);
+  });
 
-    socket.on('close', async () => {
-      if (nickname && chatRoomId) {
-        await ChatRoom.updateOne(
-          { chatRoomId },
-          { $set: { [`isOnline.${nickname}`]: false } }
-        );
-
-        const statusMessage = {
-          type: 'status',
-          chatRoomId,
-          nickname,
-          isOnline: false,
-        };
-
-        clients.forEach(client => {
-          client.write(constructReply(JSON.stringify(statusMessage)));
-        });
-      }
+  server.listen(8081, () => {
+    console.log('WebSocket 채팅 서버가 8081 포트에서 실행 중입니다.');
+  });
+}
+
+function handleWebSocketUpgrade(req, socket) {
+  const key = req.headers['sec-websocket-key'];
+  const acceptKey = generateAcceptValue(key);
+  const responseHeaders = [
+    'HTTP/1.1 101 Switching Protocols',
+    'Upgrade: websocket',
+    'Connection: Upgrade',
+    `Sec-WebSocket-Accept: ${acceptKey}`
+  ];
+
+  socket.write(responseHeaders.join('\r\n') + '\r\n\r\n');
+
+  // 클라이언트를 clients 배열에 추가
+  clients.push(socket);
+
+  socket.on('data', async buffer => {
+    try {
+      message = parseMessage(buffer);
+      if (!message) return; // 메시지가 비어 있는 경우 무시
+
+      const parsedData = JSON.parse(message);
+      const { type, chatRoomId: clientChatRoomId, nickname: clientNickname, text } = parsedData;
+      await handleClientMessage(socket, parsedData);
+    } catch (err) {
+      console.error('Error processing message:', err);
+    }
+  });
+
+  socket.on('close', async () => {
+
+      console.log(`WebSocket 연결이 종료되었습니다: ${socket.nickname}, ${socket.chatRoomId}`);
+
+      // 클라이언트 Heartbeat 맵에서 제거
+      clientHeartbeats.delete(socket);
+
+      // 클라이언트 목록에서 제거
+      clients = clients.filter((client) => client !== socket);
+
+
+      // 소켓 종료 전, 창 닫기 or hidden 때문에 이미 온라인 상태 false로 됨 (중복 로직 주석 처리)
+      // if (socket.nickname && socket.chatRoomId) {
+      //   await ChatRoom.updateOne(
+      //     { chatRoomId: socket.chatRoomId },
+      //     { $set: { [`isOnline.${socket.nickname}`]: false } }
+      //   );
+      // }
+  });
+
+  socket.on('error', (err) => {
+    console.error(`WebSocket error: ${err}`);
+    clients = clients.filter((client) => client !== socket);
+  });
+
+}
+
+// 메시지 타입 처리
+async function handleClientMessage(socket, data) {
+  const { type, chatRoomId, nickname, text, fcmToken } = data;
+
+  // 타임아웃된 소켓 차단
+  if (socket.isTimedOut) {
+    console.log(`타임아웃된 클라이언트의 재연결을 차단: ${nickname}`);
+    return;
+  }
+
+  switch (type) {
+    case 'heartbeat':
+      // console.log(`Heartbeat received from ${nickname} in room ${chatRoomId}`);
+      clientHeartbeats.set(socket, Date.now());
+      break;
+    case 'join':
+      // WebSocket에 사용자 정보 저장
+      // socket.nickname = nickname;
+      // socket.chatRoomId = chatRoomId;
+      await handleJoin(socket, chatRoomId, nickname, fcmToken);
+      break;
+    case 'message':
+      await handleMessage(chatRoomId, nickname, text);
+      break;
+    case 'leave':
+      await handleLeave(chatRoomId, nickname);
+      break;
+    case 'notice':
+      await handleSetNotice(chatRoomId, nickname, text);
+      break;
+    default:
+      console.log(`Unknown message type: ${type}`);
+  }
+}
+
+// join - 참가 메시지
+async function handleJoin(socket, chatRoomId, nickname) {
+  if (socket.isTimedOut) {
+    console.log(`타임아웃된 클라이언트의 재참여를 차단: ${nickname}`);
+    return;
+  }
+
+  // Set client properties
+  socket.chatRoomId = chatRoomId;
+  socket.nickname = nickname;
+
+  console.log(`Client joined room: ${chatRoomId}, nickname: ${nickname}`);
+
+  await ChatRoom.updateOne(
+    { chatRoomId: chatRoomId },
+    { $set: { [`isOnline.${nickname}`]:true } }
+  );
+
+  const statusMessage = {
+    type: 'status',
+    chatRoomId: chatRoomId,
+    nickname: nickname,
+    isOnline: true,
+  };
+
+  broadcastMessage(chatRoomId, statusMessage);
+
+  await ChatRoom.updateOne(
+    { chatRoomId },
+    { $set: {
+      [`isOnline.${nickname}`]: true,
+      [`lastReadLogId.${nickname}`]: null,
+      },
+    }
+  );
+
+  const chatRoom = await ChatRoom.findOne({ chatRoomId });
+
+  // 참가자 확인
+  const participantIndex = chatRoom.participants.findIndex(participant => participant.name === nickname);
+  
+  if (participantIndex !== -1) {
+      const existingParticipant = chatRoom.participants[participantIndex];
+
+      // 참가자 상태 업데이트
+      existingParticipant.isOnline = true;
+      existingParticipant.lastReadAt = new Date();
+
+      await chatRoom.save();
+    } else {
+      // 새 참가자 추가
+      const joinMessage = {
+        message: `${nickname}님이 참가했습니다.`,
+        timestamp: new Date(),
+        type: 'join'
+      };
+
+      chatRoom.participants.push({
+        name: nickname,
+        fcmTokens: parsedData.fcmToken ? [parsedData.fcmToken] : [],
+        lastReadAt: new Date(),
+        lastReadLogId: null,
+        isOnline: true,
+      });
+
+      chatRoom.messages.push(joinMessage);
+
+      await chatRoom.save();
+
+      broadcastMessage(chatRoomId, joinMessage);
+
+      console.log(`${nickname} 새 참가자로 추가`);
+    }
+
+  const previousMessages = await getChatHistory(chatRoomId);
+  if (previousMessages.length > 0) {
+    socket.write(constructReply(JSON.stringify({ type: 'previousMessages', messages: previousMessages })));
+  }
+}
+
+// meessage - 일반 메시지
+async function handleMessage(chatRoomId, nickname, text) {
+  const chatMessage = { message: text, timestamp: new Date(), type: 'message', sender: nickname };
+
+  try {
+    const updatedChatRoom = await ChatRoom.findOneAndUpdate(
+      { chatRoomId },
+      { $push: { messages: chatMessage } },
+      { new: true, fields: { messages: { $slice: -1 } } }
+    );
+
+    // 마지막에 추가된 메시지의 _id를 가져오기
+    const savedMessage = updatedChatRoom.messages[updatedChatRoom.messages.length - 1];
+
+    // 새로운 메시지 전송: 클라이언트로 메시지 브로드캐스트
+    const messageData = {
+      type: 'message',
+      chatRoomId,
+      sender: nickname,
+      message: text,
+      timestamp: chatMessage.timestamp,
+      _id: savedMessage._id  // 저장된 메시지의 _id 사용
+    };
+
+    console.log('채팅에서 Current clients:', clients.map(client => client.chatRoomId));
+
+    // broadcastMessage(chatRoomId, messageData);
+
+    clients.forEach(client => {
+      client.write(constructReply(JSON.stringify(messageData)));
+      console.log('채팅 메시지 전송:', messageData);
     });
 
-    socket.on('error', (err) => {
-      console.error(`WebSocket error: ${err}`);
-      clients = clients.filter(client => client !== socket);
+    // 오프라인 사용자에게 FCM 푸시 알림 전송
+    const chatRoom = await ChatRoom.findOne({ chatRoomId });
+    const offlineParticipants = chatRoom.participants.filter(participant => {
+      // isOnline 상태를 Map에서 가져오기
+      const isOnline = chatRoom.isOnline.get(participant.name);
+      return isOnline === false; // 정확히 false인 사용자만 필터링
     });
+
+    console.log("offlineParticipants", offlineParticipants);
+
+    // RabbitMQ에 푸시 알림 요청 발행
+    await sendPushNotificationRequest(chatRoom.chatRoomName, nickname, text, offlineParticipants, chatRoomId);
+    
+  } catch (err) {
+    console.error('Error saving message to MongoDB:', err);
+  }
+}
+
+// leave - 퇴장 메시지
+async function handleLeave(chatRoomId, nickname) {
+  await ChatRoom.updateOne(
+    { chatRoomId: clientChatRoomId },
+    { $set: { [`isOnline.${clientNickname}`]: type === 'leave' } }
+  );
+
+  const statusMessage = {
+    type: 'status',
+    chatRoomId: clientChatRoomId,
+    nickname: clientNickname,
+    isOnline: type === 'leave',
+  };
+
+  clients.forEach(client => {
+    client.write(constructReply(JSON.stringify(statusMessage)));
   });
 
-  wsServer.listen(8081, () => {
-    console.log('WebSocket 채팅 서버가 8081 포트에서 실행 중입니다.');
+  const leaveMessage = { message: `${nickname} 님이 퇴장했습니다.`, timestamp: new Date(), type: 'leave' };
+  await ChatRoom.updateOne({ chatRoomId }, { $push: { messages: leaveMessage } });
+  broadcastMessage(chatRoomId, leaveMessage);
+}
+
+async function handleSetNotice(chatRoomId, sender, message) {
+  const notice = {
+    sender,
+    message,
+    timestamp: new Date(),
+  };
+
+  try {
+    // MongoDB에 최신 공지 저장
+    await ChatRoom.updateOne(
+      { chatRoomId },
+      { $push: { notices: notice } }
+    );
+
+    // 모든 클라이언트에게 공지사항 업데이트 메시지 전송
+    const noticeMessage = {
+      type: 'notice',
+      chatRoomId,
+      sender,
+      message,
+    };
+    
+    clients.forEach(client => {
+      client.write(constructReply(JSON.stringify(noticeMessage)));
+    });
+
+    // broadcastMessage(chatRoomId, noticeMessage);
+
+    console.log('공지사항 업데이트:', noticeMessage);
+  } catch (error) {
+    console.error('공지사항 업데이트 실패:', error);
+  }
+}
+
+// Broadcast message to clients in the same chat room
+function broadcastMessage(chatRoomId, message) {
+  clients.forEach((client) => {
+    if (client.chatRoomId === chatRoomId) {
+      client.write(constructReply(JSON.stringify(message)));
+    }
   });
 }
 
+// 주기적으로 Heartbeat 상태 확인
+setInterval(async () => {
+  const now = Date.now();
+  for (const [socket, lastHeartbeat] of clientHeartbeats.entries()) {
+    if (now - lastHeartbeat > HEARTBEAT_TIMEOUT) {
+      console.log('타임아웃 대상 클라이언트:', {
+        nickname: socket.nickname,
+        chatRoomId: socket.chatRoomId,
+        lastHeartbeat: new Date(lastHeartbeat).toISOString(),
+      });
+
+      // Heartbeat 맵에서 제거
+      clientHeartbeats.delete(socket);
+
+      // 상태 플래그 설정
+      socket.isTimedOut = true;
+
+       // 소켓 연결 종료
+      socket.end();
+
+      // 클라이언트 목록에서 제거
+      clients = clients.filter((client) => client !== socket);
+
+      // 클라이언트를 오프라인으로 설정
+      console.log("Client timed out 후 오프라인 설정");
+      await ChatRoom.updateOne(
+        { [`isOnline.${socket.nickname}`]: false },
+        { [`lastReadAt.${socket.nickname}`]: new Date() }
+      );
+
+      // 클라이언트에게 연결 종료 메시지 전송
+      const timeoutMessage = JSON.stringify({
+        type: 'status',
+        nickname: socket.nickname,
+        chatRoomId: socket.chatRoomId,
+        isOnline: false,
+      });
+      
+      clients.forEach(client => {
+        client.write(constructReply(timeoutMessage));
+      });
+
+      
+    }
+  }
+}, 5000); // 5초마다 상태 확인
+
 // Sec-WebSocket-Accept 헤더 값 생성 -> env처리
 function generateAcceptValue(key) {
   return crypto.createHash('sha1').update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', 'binary').digest('base64');
@@ -305,27 +443,37 @@ function generateAcceptValue(key) {
 
 // WebSocket 메시지 파싱 함수
 function parseMessage(buffer) {
-  const byteArray = [...buffer];
-  const secondByte = byteArray[1];
-  let length = secondByte & 127;
-  let maskStart = 2;
-
-  if (length === 126) {
-    length = (byteArray[2] << 8) + byteArray[3];
-    maskStart = 4;
-  } else if (length === 127) {
-    length = 0;
-    for (let i = 0; i < 8; i++) {
-      length = (length << 8) + byteArray[2 + i];
+  try {
+    const byteArray = [...buffer];
+    const secondByte = byteArray[1];
+    let length = secondByte & 127;
+    let maskStart = 2;
+
+    if (length === 126) {
+      length = (byteArray[2] << 8) + byteArray[3];
+      maskStart = 4;
+    } else if (length === 127) {
+      length = 0;
+      for (let i = 0; i < 8; i++) {
+        length = (length << 8) + byteArray[2 + i];
+      }
+      maskStart = 10;
     }
-    maskStart = 10;
-  }
 
-  const dataStart = maskStart + 4;
-  const mask = byteArray.slice(maskStart, dataStart);
-  const data = byteArray.slice(dataStart, dataStart + length).map((byte, i) => byte ^ mask[i % 4]);
+    const dataStart = maskStart + 4;
+    const mask = byteArray.slice(maskStart, dataStart);
+    const data = byteArray.slice(dataStart, dataStart + length).map((byte, i) => byte ^ mask[i % 4]);
+
+    const decodedMessage = new TextDecoder('utf-8').decode(Uint8Array.from(data));
+
+    // JSON 유효성 검사
+    JSON.parse(decodedMessage);
 
-  return new TextDecoder('utf-8').decode(Uint8Array.from(data));
+    return decodedMessage;
+  } catch (err) {
+    console.error('Error parsing WebSocket message:', err.message);
+    return null; // 유효하지 않은 메시지는 무시
+  }
 }
 
 // 클라이언트 메시지 응답 생성 함수
@@ -353,5 +501,8 @@ function constructReply(message) {
   return Buffer.concat([Buffer.from(reply), messageBuffer]);
 }
 
+// 서버 시작 시 RabbitMQ 설정
+setupRabbitMQ();
+
 // MongoDB 연결 후 WebSocket 서버 시작
-connectMongoDB();
\ No newline at end of file
+connectMongoDB();