Socket.IO와 MongoDB를 사용한 실시간 협업 노트패드 구축
발행: (2026년 1월 3일 오전 02:50 GMT+9)
5 min read
원문: Dev.to
Source: Dev.to
Introduction
누군가와 빠르게 메모를 공유해야 했지만 회원가입 양식이나 복잡한 권한 설정에 좌절한 적이 있나요? Collaborative Notepad는 무료이며 오픈소스인 실시간 메모장으로, 메모를 만들고 링크를 공유하면 즉시 협업을 시작할 수 있습니다—계정이 필요 없습니다.
Features
- No sign‑up required → 가입 필요 없음
- Real‑time collaboration via Socket.IO → Socket.IO를 통한 실시간 협업
- Custom URLs (e.g.,
/meeting-notes) → 맞춤 URL (예:/meeting-notes) - Dark/Light mode toggle → 다크/라이트 모드 전환
- Auto‑save every 3 seconds → 3초마다 자동 저장
- Live user count display → 실시간 사용자 수 표시
실시간 데모
저장소
GitHub – collaborative‑notepad – MIT 라이선스
백엔드 스택
- Node.js + Express
- 실시간 통신을 위한 Socket.IO
- 영속성을 위한 MongoDB
- 템플릿 엔진으로 EJS
- 보안: Helmet, 속도 제한, CSP
서버 설정 (Express + Socket.IO)
// server.js
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const mongoose = require('mongoose');
const app = express();
const server = http.createServer(app);
const io = socketIo(server);
// MongoDB connection
mongoose.connect(process.env.MONGODB_URI);
// Socket.IO connection handling
io.on('connection', (socket) => {
console.log('User connected');
socket.on('join-note', async (noteId) => {
socket.join(noteId);
// Broadcast user count
io.to(noteId).emit('user-count',
io.sockets.adapter.rooms.get(noteId)?.size || 0
);
});
socket.on('note-update', async ({ noteId, content }) => {
// Save to database
await Note.findOneAndUpdate(
{ noteId },
{ content, lastModified: Date.now() }
);
// Broadcast to all users in room
socket.to(noteId).emit('note-change', content);
});
});
MongoDB 스키마
// models/Note.js
const noteSchema = new mongoose.Schema({
noteId: { type: String, unique: true, required: true },
content: { type: String, default: '' },
createdAt: { type: Date, default: Date.now },
lastModified: { type: Date, default: Date.now },
viewCount: { type: Number, default: 0 }
});
const Note = mongoose.model('Note', noteSchema);
클라이언트‑사이드 실시간 동기화
// public/js/app.js
const socket = io();
const noteId = window.location.pathname.substring(1) || 'home';
const textarea = document.getElementById('note');
const userCountElement = document.getElementById('user-count');
// Join note room
socket.emit('join-note', noteId);
// Send updates to server (debounced)
let timeout;
textarea.addEventListener('input', () => {
clearTimeout(timeout);
timeout = setTimeout(() => {
socket.emit('note-update', {
noteId,
content: textarea.value
});
}, 300);
});
// Receive updates from other users
socket.on('note-change', (content) => {
if (document.activeElement !== textarea) {
textarea.value = content;
}
});
// Update user count
socket.on('user-count', (count) => {
userCountElement.textContent = count;
});
속도 제한
// middleware/rateLimit.js
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per window
});
app.use('/api/', limiter);
콘텐츠 보안 정책
// security/csp.js
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"]
}
}));
XSS 방지
const xss = require('xss');
// Example sanitization
const sanitizedContent = xss(userInput);
Express 라우팅 맞춤 URL
app.get('/:noteId', async (req, res) => {
const noteId = req.params.noteId;
const note = await Note.findOne({ noteId }) ||
await Note.create({ noteId });
res.render('index', { note });
});
자동 저장 로직
let saveTimeout;
const AUTO_SAVE_DELAY = 3000; // 3 seconds
textarea.addEventListener('input', () => {
clearTimeout(saveTimeout);
saveTimeout = setTimeout(saveToDatabase, AUTO_SAVE_DELAY);
});
테마 지정 (CSS 사용자 정의 속성)
:root {
--bg-color: #fefae0;
--text-color: #1e3a1f;
}
[data-theme="dark"] {
--bg-color: #1e1e1e;
--text-color: #e0e0e0;
}
성능 및 신뢰성 최적화
- Debouncing 소켓 전송을 디바운싱하여 서버 부하 감소
- MongoDB indexing 빠른 노트 조회를 위한 인덱싱
- Connection pooling 효율적인 DB 사용을 위한 커넥션 풀링
- Gzip compression 미들웨어를 통한 더 빠른 자산 전달
- Socket.IO rooms 노트별 협업을 격리하기 위한 룸 활용
향후 개선 사항 (로드맵)
- 마크다운 지원
- 코드 블록에 대한 구문 강조
- 비밀번호 보호 노트
- PDF/TXT로 내보내기
- 협업 커서 위치
- 음성 노트
- 모바일 앱
기술 스택 요약
- Node.js
- Express
- Socket.IO
- MongoDB
- EJS
개발 시간
≈ 20 시간
라이선스
MIT (오픈 소스)
이 글이 도움이 되었다면 ❤️를 눌러주시고 GitHub 저장소에 별표를 달아 주세요!