- Pokiλ λ§λ²μ΄ κ°μ μ λΆλͺ¨λκ³Ό μμ΄λ€μ μν μνΈμμ© μλΉμ€μ λλ€.
- λΆλͺ¨λμ λ©λ¦¬ μλ μλ μλ OK! μμ΄λ€κ³Ό λκ»΄λ³΄μ§ λͺ»νλ μμ€ν κ²½νμ μμ보μΈμ.
- λ‘κ·ΈμΈ ν μλ μ λΆλͺ¨λμ κ³ μ μ½λλ‘ μ°κ²°νκ² λ©λλ€.
- μλ λ κ°μ§κ³ μΆμ μ λ¬Όμ κ²μνμ¬ μμ리μ€νΈμ λ±λ‘ν μ μμ΅λλ€.
- λΆλͺ¨λμ μλ κ° λ±λ‘ν μμ리μ€νΈλ₯Ό λ³΄κ³ μλ μκ² μ£Όκ³ μΆμ μ λ¬Όμ μ ννκ² λκ³ ν¬λμ λͺ¨μΌκΈ°λ₯Ό μμνκ² λ©λλ€.
- λΆλͺ¨λμ μλ μκ² λ―Έμ μ μ€ μ μμ΅λλ€.
- μλ λ λ―Έμ μ μννκ³ ν¬λμμ λ°κ² λ©λλ€.
- 31κ°μ ν¬λμμ λͺ¨μΌκ² λλ©΄ λΆλͺ¨λμ μλ μκ² μ λ¬Όμ μ£Όκ² λ©λλ€.
31κ°μ ν¬λμμ λͺ¨μ보μΈμ.
μνλ μ λ¬Όμ μ νν΄ λ³΄μΈμ.
AIλ₯Ό νμ©νμ¬ λ―Έμ μ μΆμ²λ°μ 보μΈμ.
λ―Έμ μ μμ½ν΄ 보μΈμ.
μ±ν μΌλ‘ λΆλͺ¨λκ³Ό μν΅ν΄λ³΄μΈμ.
λΆλͺ¨λκ³Ό νμ ν΅νλ₯Ό ν΄λ³΄μΈμ.
λͺ¨λ°μΌμμ μ€μΉνμ¬ μΉκ³Ό μ±μμ λͺ¨λ μ¬μ©ν΄λ³΄μΈμ.
μΊλ¦°λλ‘ ν¬λμ λ° μ λ¬Όμ μ€ κΈ°λ‘μ νμΈν΄ 보μΈμ.
λ©μμ§, νμν΅ν, λ―Έμ λ±μ μλ¦Όμ λ°μ보μΈμ.
-
Board & Wishlist CRUD μ€κ³
-
μ μ κ° Board λκΈ°νλ₯Ό μν Client-Server ν΅μ λ°©μ κ°μ
-
μλ μ Whishlist μ€μ μ λ¬Όμ μ ν, ν¬λ κ°μ 31κ° μλ£ν μ λ¬Ό μ¦μ -> Board μμ±, μμ νμ
-
λΆλͺ¨κ° μλ μκ² ν¬λμμ μ¦μ νκ±°λ, μλ κ° ν¬λμμ λΆνκ²½μ° μλ‘μ νλ©΄μ μ 보 λκΈ°ν νμ
-
μλΉμ€ λ©μΈνμ΄μ§μμλ μμ λ€μμ μ΄λ²€νΈλ€μ΄ λ°μ, λ°μ ν λλ§λ€ 보λμ μ λ³΄κ° νμ
-
μ΄κΈ° μ€κ³μ Poling λ°©μμΌλ‘ κ°κ°μ μ΄λ²€νΈκ° μ λΆ Board μ μνλ₯Ό μμ² -> μλ² κ³ΌλΆν λ°μ
-
μ²μ λ©μΈ νμ΄μ§μμ ν΄λΌμ΄μΈνΈκ° μλ²μ Boardμ μνλ₯Ό μμ²ν λκΈ°, μ΄λ²€νΈ λ°μμ μλ² μΈ‘μμ μνλ₯Ό μλ΅νλ SSE λ°©μμΌλ‘ λ³κ²½
-
-
μμ€ μ½λ
- λ©μΈνμ΄μ§ μ μμ ν΄λΌμ΄μΈνΈ μΈ‘μμ Board μν μμ² -> μλ² μΈ‘ μ²μ Board μν μλ΅ν λκΈ°
let globalVersion = 0; // Global version variable(μ μλ³μ μ§μ ) @Sse('/grape/sse/user') async sseGetBoardByUserId( @GetUser() user: User, @GetUserId() id: number, @GetUserType() type: string, ): Promise<Observable<responseSseBoardDto>> { if (type !== 'PARENT') { id = await this.AuthService.getConnectedUser(user); } const use_grape = await this.boardService.getBoardByUserId(id); return new Observable<responseSseBoardDto>((observer) => { let localVersion = 0; // Local version variable const initialData = async () => { // 맨 μ²μ 보λ μνλ₯Ό λΆλ¬μ΄(Board μ‘΄μ¬νμ§ μμ κ²½μ°) if (!use_grape) { const initialResponse: responseSseBoardDto = { data: { code: 200, success: true, grape: { id:0, blank: 0, total_grapes: 0, attached_grapes: 0, deattached_grapes: 0, }, is_existence: false, }, }; observer.next(initialResponse); localVersion = globalVersion; // Update the local version return; } // 맨 μ²μ 보λ μνλ₯Ό λΆλ¬μ΄(Board μ‘΄μ¬ν κ²½μ°) const initialResponse: responseSseBoardDto = { data: { code: 200, success: true, grape: await this.boardService.getBoardByUserId(id), is_existence: true, }, }; observer.next(initialResponse); localVersion = globalVersion; // Update the local version };
- μλ κ° ν¬λμμ λΆνκ±°λ μ¬λ¬ μ΄λ²€νΈ λ°μμ μλ²μΈ‘μμ Boardμ μν μ μ‘
//ν¬λ λΆμ°© λ²νΌ ν΄λ¦μ μ€ν ν¨μ @Post('/grape/attach') async attachBoard( ): Promise<responseBoardDto> { globalVersion += 1; // μλ²μμ μ΄λ²€νΈ λ°μ νμΈ return response } --------------------------------------------------------------------------------------- // λ€λ₯Έ μ΄λ²€νΈκ° λ°μνμ κ²½μ°(λκΈ°μ€μΈ μλ²μμ μ΄λ²€νΈ λ°μμ Board μν μλ΅) if (localVersion < globalVersion) { const use_grape = await this.boardService.getBoardByUserId(id); // 맨 μ²μ 보λ μνλ₯Ό λΆλ¬μ΄(Wishlist μ¦μ μΌλ‘ μΈν Board μ‘΄μ¬νμ§ μμ κ²½μ°) if (!use_grape) { const response: responseSseBoardDto = { data: { code: 200, success: true, grape: { id:0, blank: 0, total_grapes: 0, attached_grapes: 0, deattached_grapes: 0, }, is_existence: false, }, }; observer.next(response); localVersion = globalVersion; // Update the local version return; } // 맨 μ²μ 보λ μνλ₯Ό λΆλ¬μ΄(Board μ‘΄μ¬ν κ²½μ°) const response: responseSseBoardDto = { data: { code: 200, success: true, grape: await this.boardService.getBoardByUserId(id), is_existence: true, }, }; observer.next(response); localVersion = globalVersion; // Update the local version } }; initialData(); const intervalId = setInterval(updateData, 500); // ν΄λΌμ΄μΈνΈ μΈ‘μμ μ°κ²°μ΄ λμ΄μ‘μ κ²½μ° observer.complete = () => { clearInterval(intervalId); }; localVersion = globalVersion; return observer; });
-
-
Chat WebSocket λ°±μλ λΆλΆ μ€κ³
-
μ±ν λ΄μ μ μ₯
-
μλλ°©κ³Όμ μ±ν λ΄μ μ μ₯μ μν΄ eventGateway μΈ‘μμ Message μ 보 μ§μ μ μ₯
@SubscribeMessage('message') async handleMessage( @ConnectedSocket() socket: Socket, @MessageBody() { roomName, message, user }: MessagePayload, ) { // Save message in database this.eventService.createMessage(user.user_id, message, roomName, user.id, user.name); socket.to(roomName).emit('message', { sender_id: user.user_id, message, check_id: user.id, createdAt: new Date(), sender_name: user.name }); return { sender_id: user.user_id, message, check_id: user.id, createdAt: new Date(), sender_name: user.name }; }
-
μ μ₯λ μ±ν λ΄μ μ±ν μμ±λ μκ° μμΌλ‘ 리μ€νΈ νμμΌλ‘ ν΄λΌμ΄μΈνΈ μΈ‘μ μλ΅
async getMessage(room_name: string): Promise<Message[]> { const messages = await this.messageRepository .createQueryBuilder('message') .where('message.conversation_id = :room_name', { room_name }) .orderBy('message.createdAt', 'ASC') .getMany(); return messages ; }
-
-
μ±ν μλ¦Όμ μν μ±ν λ°© μ μ₯/λΉμ μ₯ νμ ꡬν
-
μ±ν λ°©μ μλλ°© μμμ λ©μΈμ§ λ΄μ© μλ¦ΌμΌλ‘ μ μ‘νλ κΈ°λ₯ ꡬν
-
ꡬν μμ μ μ κ° μ±ν νμ΄μ§μ μ μ₯μ μ§μ λ DBμ μ μ₯
-
μ μ κ° μ±ν νμ΄μ§μ λκ° μ DBμμ μμ
//μ μ μ±ν λ°©μ μ μ₯μ @SubscribeMessage('setUserName') async handleSetUserName( @MessageBody() data: { user_id: string }, @ConnectedSocket() socket: Socket ) { await this.eventService.createChatSocketConnection(data.user_id, socket.id); } ----------------------------------------------------------------------------------------------- // μ μ μ±ν λ°© ν΄μ₯μ @SubscribeMessage('disconnect') async handleDisconnect(@ConnectedSocket() socket: Socket) { try { const disconnectedUser = await this.eventService.findChatConnectionBySocketId(socket.id); if (disconnectedUser) { this.eventService.deleteChatConnection(disconnectedUser) } } catch (error) { this.logger.error(error); } }
-
DBμ μ μ μ‘΄μ¬ μ¬λΆμ λ°λ₯Έ μ μ₯/λΉμ μ₯ νμ
//@SubscribeMessage('message') const now_user = await this.authService.getUserById(user.id); // μ±ν λ°©μ μλλ°©μ΄ μλμ§ νμΈ const connect_userId = await this.authService.getConnectedUser_id(now_user); const check = await this.eventService.checkChatConnection(connect_userId); if (!check) { try { const connect_id = await this.authService.getConnectedUser(now_user); const pushToken = await this.pushService.getPushToeknByUserId(connect_id); const title = 'μλ‘μ΄ λ©μμ§κ° λμ°©νμ΅λλ€.'; let info; if (!message.startsWith('/static/media')) { info = message; } else { info = 'μ΄λͺ¨ν°μ½μ 보λμ΅λλ€.' } await this.pushService.push_noti(pushToken, title, info); } catch (exception) { if (exception instanceof ForbiddenException) { return { sender_id: user.user_id, message, check_id: user.id, createdAt: new Date(), sender_name: user.name }; } } }
-
-
| λΆλ₯ | κΈ°μ |
|---|---|
| Frontend | |
| Backend | |
| WebRTC | |
| Database | |
| Infrastructure/DevOps |
BE νμ₯ : λ°μ μ |
BE νμ : μ΄μμ |
BE νμ : μ μ μ§ |
FE νμ : κΉμ¬μ |
FE νμ : μ§μν |