성경 타자경기 앱 업그레이드
QR로 접속 → 실시간 타자 대회
🎯 학습 목표
- ✓Socket.IO를 활용한 실시간 멀티플레이어 구현
- ✓QR 코드 생성 및 입장 시스템 구축
- ✓실시간 리더보드 업데이트
- ✓방 관리 및 게임 상태 동기화
💻 실습: 단계별 진행
STEP 1프로젝트 구조 설정 (5분)
🤖 첫 번째 프롬프트
Next.js와 NestJS를 사용한 모노레포 구조를 만들어줘. Next.js는 apps/web 폴더에, NestJS는 apps/api 폴더에 생성해줘. pnpm workspace를 사용해줘. Socket.IO 패키지도 양쪽에 설치해줘.
📁 생성될 구조
typing-race/ ├── apps/ │ ├── api/ # NestJS 백엔드 │ └── web/ # Next.js 프론트엔드 ├── package.json # 루트 패키지 └── pnpm-workspace.yaml
STEP 2백엔드: Socket.IO 게이트웨이 구현 (10분)
🤖 두 번째 프롬프트
NestJS에 Socket.IO 게이트웨이를 만들어줘. 다음 이벤트를 처리해줘:
1. joinRoom: 사용자가 방에 입장
2. typing: 타이핑 진행 상황 전송
3. complete: 완료 시각 기록
4. disconnect: 연결 해제 처리
각 방은 최대 100명까지 참가 가능하게 해줘. 방 정보는 메모리에 Map으로 저장해줘.
🔍 핵심 로직
@WebSocketGateway()
export class TypingGateway {
@SubscribeMessage('joinRoom')
handleJoinRoom(client: Socket, data: { roomId, name }) {
client.join(data.roomId);
// 방에 있는 모든 사용자에게 알림
this.server.to(data.roomId).emit('playerJoined', data);
}
@SubscribeMessage('typing')
handleTyping(client: Socket, data: { roomId, progress }) {
// 실시간으로 다른 참가자들에게 진행 상황 전송
client.to(data.roomId).emit('playerProgress', data);
}
}STEP 3MariaDB 연동 및 기록 저장 (8분)
🤖 세 번째 프롬프트
Prisma를 사용해서 MariaDB와 연결해줘. TypingResult 모델을 만들어줘:
- roomId (문자열)
- playerName (문자열)
- text (문자열, 타이핑한 문구)
- wpm (숫자, 분당 타자수)
- accuracy (숫자, 정확도)
- completedAt (날짜)
게임 완료 시 결과를 저장하는 API도 만들어줘.
STEP 4프론트엔드: 호스트 화면 구현 (8분)
🤖 네 번째 프롬프트
Next.js로 호스트 화면을 만들어줘.
1. "방 만들기" 버튼 - 6자리 방 코드 생성
2. QR 코드 표시 - qrcode.react 라이브러리 사용
3. 참가자 목록 실시간 표시
4. "게임 시작" 버튼
5. 실시간 리더보드 - 진행률과 순위 표시
Socket.IO 클라이언트로 백엔드와 연결해줘.
🎨 화면 구성
대기 화면
- • QR 코드 (큼직하게)
- • 방 코드 (큰 글씨)
- • 참가자 수
- • 시작 버튼
게임 화면
- • 목표 성경 구절
- • 실시간 순위표
- • 각 참가자 진행률
- • 타이머
STEP 5프론트엔드: 참가자 화면 구현 (9분)
🤖 다섯 번째 프롬프트
참가자용 페이지를 만들어줘.
1. 방 코드 입력 화면
2. 이름 입력
3. 대기 화면 - "호스트가 게임을 시작할 때까지 기다려주세요"
4. 타이핑 화면 - 성경 구절과 입력 창
5. 결과 화면 - 내 순위, WPM, 정확도
모바일 최적화도 해줘. 세로 모드 화면에 맞게.
📱 모바일 UX 고려사항
- • 큰 터치 영역 (버튼 최소 44x44px)
- • 가상 키보드 공간 확보
- • 자동 스크롤 방지
- • 확대/축소 방지 (viewport 설정)
🔥 실시간 동기화 로직
1️⃣ 방 입장
// 클라이언트
socket.emit('joinRoom', { roomId: '123456', name: '김목사' });
// 서버 → 모든 참가자에게 브로드캐스트
socket.to(roomId).emit('playerJoined', { name: '김목사' });2️⃣ 실시간 타이핑 진행
// 클라이언트 - 키 입력마다 전송
onKeyPress(() => {
socket.emit('typing', {
roomId,
progress: currentLength / totalLength,
wpm: calculateWPM()
});
});3️⃣ 완료 처리
// 클라이언트
socket.emit('complete', { roomId, result: {...} });
// 서버 → DB 저장 + 모두에게 알림
await prisma.typingResult.create({ data: result });
socket.to(roomId).emit('playerCompleted', result);🚀 확장 아이디어
👥 팀전 모드
청년부 vs 장년부 팀 대항전
🎤 음성 카운트다운
"3, 2, 1, 시작!" 음성 출력
📊 통계 대시보드
역대 기록, 평균 WPM 차트
🎁 리워드 시스템
배지 획득, 레벨업 시스템
✅ 완성 체크리스트
👨🏫 강사 노트
⏰ 시간 배분: 백엔드(15분), 프론트엔드(20분), 테스트(5분)
📱 데모 준비: 실제 휴대폰으로 접속하여 시연. QR 코드 스캔하는 장면 보여주기
🎯 핵심 메시지: "오전 앱이 오후에는 100명이 동시에 쓸 수 있는 서비스가 되었습니다!"
🔧 트러블슈팅: 방화벽/네트워크 이슈 대비, 핫스팟 사용법 준비
🎉 분위기: 첫 실시간 앱 완성! 환호 유도. 실제로 게임 한 판 진행해보기