Skip to content

soo96/bambitalk-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

4 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿงก BambiTalk

BambiTalk์€ ๋ถ€๋ถ€ ๋˜๋Š” ์ปคํ”Œ์ด ์•„๊ธฐ ์ถœ์‚ฐ ์ „ํ›„์˜ ์œก์•„ ์ผ์ •์„ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•˜๊ณ , ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…์„ ํ†ตํ•ด ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ์ „์šฉ ์†Œํ†ต ์•ฑ์ž…๋‹ˆ๋‹ค.

์ผ์ •๊ณผ ํ•  ์ผ, ๋ฉ”์‹œ์ง€๋ฅผ ํ•œ ๊ณณ์—์„œ ๊ณต์œ ํ•˜๋ฉฐ ์œก์•„์— ํ•„์š”ํ•œ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์„ ๋” ์‰ฝ๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.


๐Ÿ“– ๋ชฉ์ฐจ


๐Ÿ› ๏ธ Tech Stacks

Client

TypeScript React Native

Server

TypeScript NestJS Prisma Redis Amazon S3 MySQL

Test

Jest


๐Ÿง Motivation

๊ธฐ์กด์˜ ์œก์•„ ๊ด€๋ จ ์•ฑ๋“ค์€ ๋Œ€๋ถ€๋ถ„ ์ •๋ณด ์ œ๊ณต์ด๋‚˜ ์ปค๋ฎค๋‹ˆํ‹ฐ ์ค‘์‹ฌ์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์–ด, ๋ถ€๋ถ€ ๋˜๋Š” ์ปคํ”Œ์ด ํ•จ๊ป˜ ์ผ์ •์„ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ค์‹œ๊ฐ„์œผ๋กœ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋Š” ์ „์šฉ ์•ฑ์€ ์ฐพ๊ธฐ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค.

์œก์•„๋Š” ํ•œ ์‚ฌ๋žŒ๋งŒ์˜ ๋ชซ์ด ์•„๋‹ˆ๋ฉฐ, ํ•จ๊ป˜ ๊ณ„ํšํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๊ณผ์ •์ด ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์„œ๋กœ์˜ ์ผ์ •์ด๋‚˜ ํ•  ์ผ์„ ๊ณต์œ ํ•˜๊ธฐ ์–ด๋ ต๊ณ , ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜๋„ ์—ฌ๋Ÿฌ ์•ฑ์„ ์˜ค๊ฐ€๋ฉฐ ๋ฒˆ๊ฑฐ๋กญ๊ฒŒ ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

BambiTalk์€ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ์œก์•„ ์ผ์ •๊ณผ ํ•  ์ผ์„ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…์œผ๋กœ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋Š” โ€˜1:1 ์œก์•„ ์ „์šฉ ์†Œํ†ต ์•ฑโ€™์„ ๋ชฉํ‘œ๋กœ ๊ฐœ๋ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ•น๏ธ Features

BambiTalk์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์— ์ง‘์ค‘ํ•ฉ๋‹ˆ๋‹ค.

1. ํ•จ๊ป˜ ์“ฐ๋Š” ์œก์•„ ์ผ์ • & ํ•  ์ผ ๊ด€๋ฆฌ

๋ˆ„๊ฐ€ ์–ด๋–ค ์ผ์ •์„ ๋“ฑ๋กํ–ˆ๋Š”์ง€, ์˜ค๋Š˜ ํ•ด์•ผ ํ•  ์ผ์ด ๋ฌด์—‡์ธ์ง€ ํ•œ๋ˆˆ์— ํ™•์ธํ•˜๊ณ  ํ•จ๊ป˜ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.
์บ˜๋ฆฐ๋”์—๋Š” ๋ถ€๋ถ€ ์ค‘ ๋ˆ„๊ฐ€ ์ผ์ •์„ ๋“ฑ๋กํ–ˆ๋Š”์ง€ ์ด๋ชจ์ง€๋กœ ๊ตฌ๋ถ„๋˜๋ฉฐ, ๊ฐ ์ผ์ •์€ ์‹œ๊ฐ„์ˆœ์œผ๋กœ ์ •๋ฆฌ๋˜๊ณ  ์™„๋ฃŒ ์—ฌ๋ถ€๋„ ์ฒดํฌ๋ฐ•์Šค๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€ ๋ณด๊ธฐ

2. ์‹ค์‹œ๊ฐ„ ์ปคํ”Œ ์ฑ„ํŒ… ๊ธฐ๋Šฅ

์†Œ์ค‘ํ•œ ์œก์•„ ๋Œ€ํ™”๋ฅผ ์œ„ํ•œ ์ „์šฉ ์ฑ„ํŒ…๋ฐฉ!

์„œ๋กœ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฃผ๊ณ ๋ฐ›๊ณ , ์ผ์ •์ด๋‚˜ ํ•  ์ผ๊ณผ ์—ฐ๊ฒฐ๋œ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜๋„ ๋งค๋„๋Ÿฝ๊ฒŒ ์ด์–ด์ง‘๋‹ˆ๋‹ค.
๋˜ํ•œ, ์‚ฌ์ง„๊ณผ ๋™์˜์ƒ๋„ ์ž์œ ๋กญ๊ฒŒ ์ „์†กํ•  ์ˆ˜ ์žˆ์–ด ์œก์•„ ์ˆœ๊ฐ„์„ ์ƒ์ƒํ•˜๊ฒŒ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€ ๋ณด๊ธฐ


๐Ÿ”ฅ Challenges

1. ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…์œผ๋กœ ์‚ฌ์ง„ ๋ฐ ๋™์˜์ƒ ํŒŒ์ผ ์ „์†กํ•˜๊ธฐ ๐Ÿ“ฌ

BambiTalk์˜ ์ฑ„ํŒ… ๊ธฐ๋Šฅ์€ ๋‹จ์ˆœํ•œ ํ…์ŠคํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ๋„˜์–ด, ์‚ฌ์ง„๊ณผ ๋™์˜์ƒ ๊ฐ™์€ ๋ฏธ๋””์–ด ํŒŒ์ผ๋„ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
์ดˆ๊ธฐ์—๋Š” WebSocket ๊ธฐ๋ฐ˜ ์ฑ„ํŒ…์— ํŒŒ์ผ ์ „์†ก ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด, ํŒŒ์ผ์„ base64๋กœ ์ธ์ฝ”๋”ฉํ•ด ์†Œ์ผ“ ๋ฉ”์‹œ์ง€์— ํฌํ•จ์‹œํ‚ค๋Š” ๋ฐฉ์‹์„ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿšจ ๋ฌธ์ œ ์ƒํ™ฉ

๊ฐค๋Ÿฌ๋ฆฌ์—์„œ ์„ ํƒํ•œ ์ด๋ฏธ์ง€๋Š” ๋ฌธ์ œ์—†์ด ์ „์†ก๋˜์—ˆ์ง€๋งŒ, ์นด๋ฉ”๋ผ๋กœ ์ง์ ‘ ์ดฌ์˜ํ•œ ์‚ฌ์ง„์ด๋‚˜ ๋™์˜์ƒ์„ ์ „์†กํ•  ๊ฒฝ์šฐ, ์†Œ์ผ“ ์—ฐ๊ฒฐ์ด ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ๋Š์–ด์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.


1.1. ํ™”๋ฉด ํฌ์ปค์Šค ์ฒ˜๋ฆฌ ๋ฐฉ์‹

์ฒ˜์Œ์—๋Š” ์ด ๋ฌธ์ œ๊ฐ€ ํ™”๋ฉด ํฌ์ปค์Šค ์ฒ˜๋ฆฌ ๋ฐฉ์‹ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.
ํ˜„์žฌ ์ฑ„ํŒ…๋ฐฉ์€ useFocusEffect ํ›…์„ ์ด์šฉํ•ด, ํ™”๋ฉด์— ์ง„์ž…ํ•˜๋ฉด ์†Œ์ผ“์„ ์—ฐ๊ฒฐํ•˜๊ณ  ๋ฒ—์–ด๋‚˜๋ฉด ํ•ด์ œํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋กœ ์ธํ•ด ์™ธ๋ถ€ ์•ฑ์ธ ์นด๋ฉ”๋ผ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด์„œ ์ฑ„ํŒ…๋ฐฉ ํฌ์ปค์Šค๊ฐ€ ์ž ์‹œ ํ•ด์ œ๋˜๊ณ , ๊ทธ ์ˆœ๊ฐ„ ์†Œ์ผ“ ์—ฐ๊ฒฐ์ด ๋Š๊ธฐ๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์˜€์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ๊ธฐ์กด์— useRef๋กœ ๊ด€๋ฆฌํ•˜๋˜ ์†Œ์ผ“ ๊ฐ์ฒด๋ฅผ Zustand ์Šคํ† ์–ด๋กœ ์˜ฎ๊ฒจ ์ „์—ญ์—์„œ ์†Œ์ผ“ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ตฌ์กฐ ๊ฐœ์„  ์ดํ›„์—๋„ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ณ , ๊ฒฐ๊ตญ ๊ทผ๋ณธ์ ์ธ ์›์ธ์€ ์ „์†ก ๋ฐฉ์‹ ์ž์ฒด์— ์žˆ์Œ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

์นด๋ฉ”๋ผ๋กœ ์ดฌ์˜ํ•œ ํŒŒ์ผ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์šฉ๋Ÿ‰์ด ํฌ๊ณ , ์ด๋ฅผ base64๋กœ ์ธ์ฝ”๋”ฉํ•ด WebSocket์œผ๋กœ ์ „์†กํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ฐ์ดํ„ฐ ํฌ๊ธฐ๊ฐ€ ๊ณผ๋„ํ•˜๊ฒŒ ์ฆ๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด๋กœ ์ธํ•ด ์†Œ์ผ“ ์—ฐ๊ฒฐ์ด ๊ณผ๋ถ€ํ•˜๋กœ ๋Š๊ธฐ๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ฆ‰, WebSocket์„ ํ†ตํ•ด ๋Œ€์šฉ๋Ÿ‰ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์ „์†กํ•˜๋Š” ๋ฐฉ์‹์€ ๊ธฐ์ˆ ์ ์œผ๋กœ ๊ตฌ์กฐ์  ํ•œ๊ณ„๊ฐ€ ์žˆ๋Š” ๋ฐฉ์‹์ด์—ˆ์Šต๋‹ˆ๋‹ค.


1.2. ํŒŒ์ผ ์ „์†ก๊ณผ ๋ฉ”์‹œ์ง€ ์ „์†ก์„ ๋ถ„๋ฆฌ

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ํŒŒ์ผ ์ „์†ก๊ณผ ๋ฉ”์‹œ์ง€ ์ „์†ก์„ ์™„์ „ํžˆ ๋ถ„๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋ฆฌํŒฉํ† ๋ง์„ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ํŒŒ์ผ ์—…๋กœ๋“œ ์ „์šฉ API (POST /api/v1/files)๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ์ดฌ์˜ํ•˜๊ฑฐ๋‚˜ ์„ ํƒํ•œ ํŒŒ์ผ์„ ํ•ด๋‹น API์— ๋จผ์ € ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
  • ์„œ๋ฒ„๋Š” ํŒŒ์ผ์„ S3์— ์ €์žฅํ•œ ๋’ค, ํด๋ผ์ด์–ธํŠธ์— Signed URL์„ ์‘๋‹ต์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์ดํ›„ ํด๋ผ์ด์–ธํŠธ๋Š” ์ด URL๊ณผ ๋ฉ”์‹œ์ง€ ํƒ€์ž…(์˜ˆ: IMAGE, VIDEO)๋งŒ ํฌํ•จํ•œ ๋ฉ”์‹œ์ง€๋ฅผ WebSocket์œผ๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ WebSocket ๋ฉ”์‹œ์ง€์—๋Š” ์‹ค์ œ ํŒŒ์ผ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ, ๊ฐ€๋ณ๊ณ  ์•ˆ์ „ํ•œ ๋งํฌ ์ •๋ณด๋งŒ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด ๋Œ€์šฉ๋Ÿ‰ ์ „์†ก์œผ๋กœ ์ธํ•œ ์†Œ์ผ“ ์—ฐ๊ฒฐ ์ข…๋ฃŒ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ์‹ค์‹œ๊ฐ„์„ฑ๊ณผ ์•ˆ์ •์„ฑ์„ ๋ชจ๋‘ ๊ฐ–์ถ˜ ๋ฏธ๋””์–ด ๋ฉ”์‹œ์ง€ ์ „์†ก ๊ธฐ๋Šฅ์„ ์™„์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๊ฒฝํ—˜์„ ํ†ตํ•ด, WebSocket์€ ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์—๋Š” ์ ํ•ฉํ•˜์ง€๋งŒ, ๋Œ€์šฉ๋Ÿ‰ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ๋Š” ๋ฐ๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์„ ๋‹ค์‹œ ํ•œ๋ฒˆ ๊นจ๋‹ฌ์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.



2. ๋ฉ”์‹œ์ง€ ์ฝ์Œ ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ๐Ÿ‘€

๊ธฐ์กด์˜ ์ฑ„ํŒ… ๊ธฐ๋Šฅ์— ๋”ํ•ด, ๋ฉ”์‹œ์ง€ ์ฝ์Œ ์ƒํƒœ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ •ํ™•ํ•˜๊ฒŒ ๋ฐ˜์˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ์—๋Š” ์ฝ์Œ ์ƒํƒœ ๋™๊ธฐํ™”๋ฅผ ์œ„ํ•ด Polling ๋ฐฉ์‹๋„ ๊ณ ๋ คํ–ˆ์ง€๋งŒ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์„œ๋ฒ„์— ์ฃผ๊ธฐ์ ์œผ๋กœ ์ƒํƒœ๋ฅผ ์š”์ฒญํ•ด์•ผ ํ•˜๋ฏ€๋กœ ํŠธ๋ž˜ํ”ฝ๊ณผ ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„.
  • ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์€ ์‹œ์ ๊ณผ ๋™๊ธฐํ™”์— ์‹œ๊ฐ„์ฐจ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ.

๋Œ€์‹  WebSocket์„ ํ™œ์šฉํ•ด, ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์—์„œ๋งŒ ์ฝ์Œ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐฉํ–ฅ์„ ์žก์•˜์Šต๋‹ˆ๋‹ค

  1. ์‚ฌ์šฉ์ž๊ฐ€ ์ฑ„ํŒ…๋ฐฉ์— ์ ‘์†ํ–ˆ์„ ๋•Œ
  2. receive_message ์ด๋ฒคํŠธ์— ์‘๋‹ตํ–ˆ์„ ๋•Œ

์ด ๋‘ ์‹œ์ ์€ ๋ชจ๋‘ ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๊ณ  ์žˆ๋Š” ์ƒํƒœ์ž„์„ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ณ„๋„์˜ ์ฃผ๊ธฐ์  ํ™•์ธ ์—†์ด๋„ ์ฝ์Œ ์ƒํƒœ๋ฅผ ์ •ํ™•ํ•˜๊ณ  ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.


2.1. ํด๋ผ์ด์–ธํŠธ์—์„œ์˜ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  ๋ฐ ์ฝ์Œ ์ฒ˜๋ฆฌ

ํด๋ผ์ด์–ธํŠธ๋Š” ์ฑ„ํŒ…๋ฐฉ์— ์ ‘์†ํ•œ ์ƒํƒœ์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•˜๋ฉด, ์ฆ‰์‹œ read_all_messages ์ด๋ฒคํŠธ๋ฅผ ์„œ๋ฒ„์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ์ด ์ด๋ฒคํŠธ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์‹ค์ œ๋กœ ์ฝ์€ ์ˆœ๊ฐ„ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ, ์ฝ์Œ ์ฒ˜๋ฆฌ ํƒ€์ด๋ฐ์ด ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.

socketInstance.on('receive_message', (message) => {
  handleMessageReceived(message);
  readAllMessages(); // read_all_messages ์ด๋ฒคํŠธ emit
});

.
.
.

const readAllMessages = () => {
  if (!socket) return;

  socket.emit('read_all_messages');
};

๋˜ํ•œ ์†Œ์ผ“ ์—ฐ๊ฒฐ ์งํ›„(์ฑ„ํŒ…๋ฐฉ ์ง„์ž… ์‹œ)์—๋„ ์„œ๋ฒ„ ์ธก์—์„œ ์ž๋™์œผ๋กœ ์ฝ์Œ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.


2.2. ์„œ๋ฒ„์—์„œ์˜ ์ฝ์Œ ์ฒ˜๋ฆฌ

์„œ๋ฒ„๋Š” ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์—์„œ ์ฝ์Œ ์ฒ˜๋ฆฌ ๋กœ์ง์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค


  1. ์†Œ์ผ“ ์—ฐ๊ฒฐ ์‹œ์ 
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฑ„ํŒ…๋ฐฉ์— ์ž…์žฅํ•˜๋ฉด, ํ•ด๋‹น ์ปคํ”Œ ๋ฐฉ(couple-{id})์— ์†Œ์ผ“์„ joinํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ ์งํ›„, DB์—์„œ ํ•ด๋‹น ์œ ์ €๊ฐ€ ๋ณด๋‚ด์ง€ ์•Š์€ ๋ชจ๋“  ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์Œ ์ฒ˜๋ฆฌํ•˜๊ณ ,
  • ๊ฐ™์€ ๋ฐฉ์— ์žˆ๋Š” ์ƒ๋Œ€๋ฐฉ์—๊ฒŒ update_read_status ์ด๋ฒคํŠธ๋ฅผ ์ „์†กํ•˜์—ฌ, ์ƒ๋Œ€๋ฐฉ ํ™”๋ฉด์—์„œ๋„ ๋ฉ”์‹œ์ง€๊ฐ€ ์ฝํžŒ ์ƒํƒœ๋กœ ํ‘œ์‹œ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

  1. read_all_messages ์ด๋ฒคํŠธ ์ˆ˜์‹  ์‹œ
  • ์‚ฌ์šฉ์ž๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ์ฝ์Œ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด, ์„œ๋ฒ„๋Š” ๋™์ผํ•œ ์ฒ˜๋ฆฌ๋ฅผ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

    @SubscribeMessage('read_all_messages')
    async readAllMessages(@ConnectedSocket() client: Socket) {
      await this.messageUseCase.readAllMessages(client.data.coupleId, client.data.userId);
      this.server.to(`couple-${client.data.coupleId}`).emit('update_read_status', client.data.userId);
    }

2.3. ํด๋ผ์ด์–ธํŠธ์—์„œ ์‹ค์‹œ๊ฐ„ ์ฝ์Œ ์ฒ˜๋ฆฌ

์ด ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด, ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์€ ์‹œ์ ์—๋งŒ ์„œ๋ฒ„์™€ ์ฝ์Œ ์ƒํƒœ๋ฅผ ๋™๊ธฐํ™”ํ•˜๋ฉฐ, ์ƒ๋Œ€๋ฐฉ์€ update_read_status ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ์ž์‹ ์˜ ๋ฉ”์‹œ์ง€๊ฐ€ ์ฝํ˜”์Œ์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



3. Redis๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ดˆ๋Œ€์ฝ”๋“œ๋กœ 1:1 ์ปคํ”Œ ๋งค์นญ ๊ตฌํ˜„

BambiTalk์˜ ๋ชจ๋“  ์ผ์ •, ์ฑ„ํŒ…, ์•Œ๋ฆผ ๊ธฐ๋Šฅ์€ ์ปคํ”Œ ๋‹จ์œ„(coupleId)๋กœ ์—ฐ๋™๋˜์–ด์•ผ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ํšŒ์›๊ฐ€์ž… ์งํ›„์—๋Š” ๋‘ ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ดˆ๋Œ€ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์„œ๋กœ๋ฅผ ์—ฐ๊ฒฐํ•œ ๋’ค, ์ปคํ”Œ๋กœ ๋งค์นญ๋œ ์ƒํƒœ์—์„œ๋งŒ ์„œ๋น„์Šค๋ฅผ ์˜จ์ „ํžˆ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.


3.1. ๋ฐœ๊ธ‰ํ•œ ์ดˆ๋Œ€์ฝ”๋“œ๋ฅผ ์–ด๋””์— ์ €์žฅํ• ๊นŒ?

์ดˆ๋Œ€ ์ฝ”๋“œ๋ฅผ ๋ฐœ๊ธ‰ํ•œ ๋’ค, ์ด๋ฅผ ์–ด๋””์— ์ €์žฅํ•˜๊ณ  ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ• ์ง€ ๊ณ ๋ฏผ์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค.
์ฒ˜์Œ์—๋Š” DB์˜ Couple ํ…Œ์ด๋ธ”์— inviteCode ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•ด ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ๊ณ ๋ คํ–ˆ์ง€๋งŒ, ์ด ๊ฒฝ์šฐ ์ดˆ๋Œ€ ์ฝ”๋“œ ์œ ํšจ์„ฑ ํ™•์ธ์„ ์œ„ํ•ด ๋งค๋ฒˆ DB๋ฅผ ์กฐํšŒํ•ด์•ผ ํ•˜๋Š” ๋น„ํšจ์œจ์ ์ธ ๊ตฌ์กฐ๋ผ๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์‹ , ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ์„ค์ •๊ณผ ์ž๋™ ์‚ญ์ œ๊ฐ€ ๊ฐ€๋Šฅํ•œ Redis๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
Redis๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ดˆ๋Œ€ ์ฝ”๋“œ๊ฐ€ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์ž๋™์œผ๋กœ ์‚ญ์ œ๋˜๋ฏ€๋กœ, ๋ณ„๋„์˜ ์ •๋ฆฌ ์ž‘์—… ์—†์ด๋„ ๊ฐ€๋ณ๊ณ  ํšจ์œจ์ ์ธ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ด์กŒ์Šต๋‹ˆ๋‹ค.


3.2. Redis ํ‚ค ์„ค๊ณ„

์ดˆ๋Œ€ ์ฝ”๋“œ๋ฅผ Redis์— ์ €์žฅํ•  ๋•Œ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‘ ๊ฐ€์ง€ ํ‚ค ๊ตฌ์กฐ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ‚ค ์ด๋ฆ„ ์—ญํ•  TTL
invite:{inviteCode} ์ฝ”๋“œ ์ž…๋ ฅ ์‹œ ์กฐํšŒ์šฉ -> coupleId, userId ์ €์žฅ 15๋ถ„
couple:{coupleId}:invite ์ค‘๋ณต ๋ฐœ๊ธ‰ ๋ฐฉ์ง€์šฉ -> inviteCode ์ €์žฅ 15๋ถ„

  1. invite:{code} โ€” ์ฝ”๋“œ ์ž…๋ ฅ ์‹œ ์กฐํšŒ์šฉ
  • ์ดˆ๋Œ€์ฝ”๋“œ๋ฅผ ๋ฐ›์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ดˆ๋Œ€ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๋•Œ, ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ ์–ด๋–ค ์ปคํ”Œ(coupleId)์— ์†ํ•œ ๊ฒƒ์ด๋ฉฐ, ๋ˆ„๊ฐ€ ์ดˆ๋Œ€ํ•œ(userId) ๊ฒƒ์ธ์ง€๋ฅผ ์ฆ‰์‹œ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ์ด ํ‚ค ํ•˜๋‚˜๋งŒ์œผ๋กœ ์ดˆ๋Œ€ ์ฝ”๋“œ์˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ๊ณผ ์—ฐ๊ฒฐ ๋Œ€์ƒ ์ •๋ณด ํ™•์ธ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ,
  • ์ฝ”๋“œ ์‚ฌ์šฉ์ด ์™„๋ฃŒ๋˜๋ฉด ํ•ด๋‹น ํ‚ค๋งŒ ์‚ญ์ œํ•ด๋„ ๊ด€๋ จ ์ •๋ณด๊ฐ€ ๋ชจ๋‘ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.
  1. couple:{coupleId}:invite โ€” ์ค‘๋ณต ๋ฐœ๊ธ‰ ๋ฐฉ์ง€์šฉ
  • ํ•œ ์ปคํ”Œ์ด ์—ฌ๋Ÿฌ ์ดˆ๋Œ€ ์ฝ”๋“œ๋ฅผ ๋™์‹œ์— ๋ฐœ๊ธ‰ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ํ•œ ํ‚ค์ž…๋‹ˆ๋‹ค.
  • ์ดˆ๋Œ€ ์ฝ”๋“œ๋ฅผ ๋ฐœ๊ธ‰ํ•  ๋•Œ, ๋จผ์ € ์ด ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ๊ธฐ์กด ์ฝ”๋“œ๊ฐ€ ์•„์ง ์œ ํšจํ•œ ๊ฒฝ์šฐ์—๋Š” ์žฌ๋ฐœ๊ธ‰ํ•˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ๋งŒ๋ฃŒ์‹œ๊ฐ„(TTL)์„ ์„ค์ •ํ•จ์œผ๋กœ์จ, ์ดˆ๋Œ€ ์ฝ”๋“œ ์œ ํšจ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์ž๋™์œผ๋กœ ๋งŒ๋ฃŒ๋˜๋„๋ก ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ํ‚ค๋กœ ์ธํ•ด ์ดˆ๋Œ€ ์ฝ”๋“œ ๋ฐœ๊ธ‰ ๋กœ์ง์—์„œ ์ค‘๋ณต ์ƒ์„ฑ์„ ํšจ๊ณผ์ ์œผ๋กœ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ ์ดˆ๋Œ€ ์ฝ”๋“œ ์ž์ฒด์˜ ์ •๋ณด์™€, ์ปคํ”Œ ๋‹จ์œ„๋กœ ๋ฐœ๊ธ‰ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜๊ธฐ ์œ„ํ•œ ์ •๋ณด๋ฅผ ๋ถ„๋ฆฌํ•ด ์ €์žฅํ•จ์œผ๋กœ์จ, ์ดˆ๋Œ€ ์ฝ”๋“œ ๊ธฐ๋Šฅ์„ ๋ณด๋‹ค ์•ˆ์ •์ ์œผ๋กœ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ”— Repository Links

ํด๋ผ์ด์–ธํŠธ ๋ ˆํฌ์ง€ํ† ๋ฆฌ | ์„œ๋ฒ„ ๋ ˆํฌ์ง€ํ† ๋ฆฌ


๐Ÿ—“๏ธ Schedule

ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„ : 2025.06.23(์›”) ~ 2025.07.18(๊ธˆ)

  • 1์ฃผ์ฐจ : ์•„์ด๋””์–ด ์„ ์ • ๋ฐ ๊ธฐํšŒ
  • 2~4์ฃผ์ฐจ : ๊ฐœ๋ฐœ

์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ๊ณ„ํš

2์ฃผ์ฐจ

  • ์ฑ„ํŒ… ์•ฑ ํ‘ธ์‹œ ์•Œ๋ฆผ ๊ธฐ๋Šฅ
  • ์ผ์ • ๋“ฑ๋ก ๋ฐ ํ•˜๋ฃจ ์ „ ๋ฆฌ๋งˆ์ธ๋“œ ํ‘ธ์‹œ ์•Œ๋ฆผ ๊ธฐ๋Šฅ
  • ์ฑ„ํŒ… ํƒญ๋ฒ„ํŠผ ์•ˆ์ฝ์Œ ๋ฉ”์‹œ์ง€ ์นด์šดํŠธ ๋ฑƒ์ง€
  • ์• ํ”Œ ๋กœ๊ทธ์ธ

3์ฃผ์ฐจ

  • ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์ž‘์„ฑ
  • ๊ฒŒ์ŠคํŠธ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ
  • ์›น์†Œ์ผ“ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published