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",     // 蹂�寃쏀븷 �쒕ぉ (�쒕ぉ 蹂�寃� �덊븷嫄곕㈃ 湲곗〈 �쒕ぉ�� �l뼱�쇳븿 * -> 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();