Skip to Content
๐Ÿš€ ๋Œ€ํ‘œ ํ”„๋กœ์ ํŠธ๐Ÿ“Š ์›น ์‚ฌ์šฉ์ž ํ–‰๋™ ๋ถ„์„ ๋Œ€์‹œ๋ณด๋“œ โ€“ MongoDash (์„ค๊ณ„ยท์ง„ํ–‰ ์ค‘) ๋Œ€์‹œ๋ณด๋“œ

๐Ÿ“Š ์›น ์‚ฌ์šฉ์ž ํ–‰๋™ ๋ถ„์„ ๋Œ€์‹œ๋ณด๋“œ โ€“ MongoDash (์„ค๊ณ„ยท์ง„ํ–‰ ์ค‘)

๐Ÿ“… 2025.11.23 ~ ์ง„ํ–‰ ์ค‘๐Ÿ‘ฅ 1๋ช…๐Ÿ›  Kotlin, Spring Boot, MongoDB, Redis, Docker, WSL

1.๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ฐœ์š”

MongoDash๋Š” ์›น ํŽ˜์ด์ง€ ๋‚ด์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ํด๋ฆญ, ํ˜ธ๋ฒ„, ํ˜ธ๋ฒ„ ์œ ์ง€ ์‹œ๊ฐ„ ๋“ฑ์˜ ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ , ์ด๋ฅผ ๋ถ„์„ยท์‹œ๊ฐํ™”ํ•˜๋Š” ๋Œ€์‹œ๋ณด๋“œ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

๋งŒ๋“ค๊ฒŒ ๋œ ๋ฐฐ๊ฒฝ

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

์ฃผ์š” ๋ชฉ์ 

  • ํŠน์ • UI ์˜์—ญ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋จธ๋ฌผ๋ €๋Š”์ง€ ๋ถ„์„
  • ํด๋ฆญ ๋ฐœ์ƒ ์œ„์น˜ยท๋นˆ๋„ยทํŒจํ„ด ํŒŒ์•…
  • ํ˜ธ๋ฒ„ ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ๊ด€์‹ฌ๋„ ๋ถ„์„
  • ํฌํŠธํด๋ฆฌ์˜ค ๊ฐœ์„ ์„ ์œ„ํ•œ ์ •๋Ÿ‰์  ๊ทผ๊ฑฐ ์ œ๊ณต

ํ˜„์žฌ๋Š” ๊ธฐํš/์„ค๊ณ„ ๋‹จ๊ณ„์ด๋ฉฐ, MongoDB๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ด๋ฒคํŠธ ๋กœ๊ทธ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์ˆ˜์ง‘โ€ฏโ†’โ€ฏ์ €์žฅโ€ฏโ†’โ€ฏ์กฐํšŒ ํ•˜๋Š” ์„œ๋ฒ„ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ตฌ์„ฑ ์ค‘์ž…๋‹ˆ๋‹ค.

2.โš™๏ธ ์‹œ์Šคํ…œ ๊ตฌ์กฐ (์„ค๊ณ„ ๋‹จ๊ณ„)

  1. ํด๋ผ์ด์–ธํŠธ โ€“ Event Collector (ํ”„๋ก ํŠธ)

    • ์ˆ˜์ง‘ํ•  ์ด๋ฒคํŠธ
      • mousemove (์ขŒํ‘œ๋งŒ, ์ผ์ • ๊ฐ„๊ฒฉ ์ƒ˜ํ”Œ๋ง)
      • click (์ขŒํ‘œโ€ฏ+โ€ฏtimestamp)
      • mouseenter / mouseleave (hover ์‹œ์ž‘/์ข…๋ฃŒ ์‹œ๊ฐ„)
      • hoverDuration (ํ˜ธ๋ฒ„ ์œ ์ง€ ์‹œ๊ฐ„ ๊ณ„์‚ฐ)
    • ์ „์†ก ๋ฐฉ์‹
      • 5์ดˆโ€ฏorโ€ฏ300๊ฑด ๋‹จ์œ„๋กœ ๋ฐฐ์น˜ ์ „์†ก
      • ์ด๋ฒคํŠธ๋ฅผ ์ฆ‰์‹œ ์„œ๋ฒ„์— ๋ณด๋‚ด์ง€ ์•Š๊ณ  ๋ฉ”๋ชจ๋ฆฌ ํ์— ์ €์žฅ โ†’ ์ผ์ •๋Ÿ‰ ์Œ“์ด๋ฉด POST ํ˜ธ์ถœ
  2. ์„œ๋ฒ„ โ€“ Kotlinโ€ฏ+โ€ฏSpring Boot

    • ๋น„๋™๊ธฐ API๋ฅผ ํ†ตํ•ด ๋Œ€๋Ÿ‰ ์ด๋ฒคํŠธ ์ˆ˜์‹ 
    • JSON ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๋“ค์–ด์˜จ ์ด๋ฒคํŠธ๋ฅผ ํŒŒ์‹ฑ
    • ๊ธฐ๋ณธ์ ์œผ๋กœ MongoDB์— ์ €์žฅํ•˜๋˜, ์ €์žฅ ๋ถ€ํ•˜๊ฐ€ ๋†’์„ ๋•Œ๋ฅผ ๋Œ€๋น„ํ•ด Redis ํ ์‚ฌ์šฉ ๊ณ ๋ ค
  3. MongoDB โ€“ Event Store

    • ์„ธ๋ถ€ ์ด๋ฒคํŠธ๋ฅผ Document ํ˜•ํƒœ๋กœ ์ €์žฅ
    • ํด๋ฆญ/ํ˜ธ๋ฒ„๋ฅผ ๋‹ค๋ฅธ ์ปฌ๋ ‰์…˜์œผ๋กœ ๋ถ„๋ฆฌํ•˜๊ฑฐ๋‚˜, ํ•˜๋‚˜์˜ ์ปฌ๋ ‰์…˜์— type ํ•„๋“œ๋กœ ๊ตฌ๋ถ„ํ• ์ง€ ์„ค๊ณ„ ๊ฒ€ํ†  ์ค‘
    • TTL ์ธ๋ฑ์Šค๋กœ ์˜ค๋ž˜๋œ ๋กœ๊ทธ ์ž๋™ ์ œ๊ฑฐ ๊ธฐ๋Šฅ ์˜ˆ์ •
  4. Dashboard API

    • ํŠน์ • ์‹œ๊ฐ„๋Œ€๋ณ„ ํด๋ฆญ ํžˆํŠธ๋งต ์ƒ์„ฑ
    • UI ์š”์†Œ๋ณ„ ํ‰๊ท  ํ˜ธ๋ฒ„ ์‹œ๊ฐ„ ๊ณ„์‚ฐ
    • ํŽ˜์ด์ง€๋ณ„ ๊ด€์‹ฌ๋„ ๋ถ„์„ API ์ œ๊ณต

3.๐Ÿ“Œ ํ˜„์žฌ๊นŒ์ง€ ์ง„ํ–‰๋œ ๋ถ€๋ถ„

  • WSLโ€ฏ+โ€ฏDocker๋ฅผ ํ™œ์šฉํ•œ MongoDB ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๊ตฌ์ถ•
    • mongod ์‹คํ–‰ ๋ฐ ํฌํŠธ ํฌ์›Œ๋”ฉ
    • Compass ๋กœ DB/์ปฌ๋ ‰์…˜ ์กฐํšŒ ์„ฑ๊ณต
    • mongosh๋Š” tar.gz ๋ฐ”์ด๋„ˆ๋ฆฌ ์„ค์น˜๋กœ ํ•ด๊ฒฐ
  • Kotlinโ€ฏ+โ€ฏSpring Boot ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ ๊ตฌ์กฐ ์ƒ์„ฑ
    • Gradleโ€ฏ+โ€ฏKotlin DSL ๊ธฐ๋ฐ˜ ์„ค์ •
    • MongoConfig ๋ฐ Repository ๋™์ž‘ ํ™•์ธ
    • /events API ์—”๋“œํฌ์ธํŠธ ์ž‘์—… ์ค‘

4.๐Ÿ“ ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ (์„ค๊ณ„)

ํด๋ฆญ ์ด๋ฒคํŠธ

{ "type": "click", "sessionId": "abc-123", "timestamp": 1732501205000, "x": 500, "y": 620, "target": "#login-button" }

ํ˜ธ๋ฒ„ ์‹œ์ž‘ / ์ข…๋ฃŒ ์ด๋ฒคํŠธ

{ "type": "hover_start", "sessionId": "abc-123", "timestamp": 1732501205000, "x": 320, "y": 450, "target": "#menu-item-1" }
{ "type": "hover_end", "sessionId": "abc-123", "timestamp": 1732501208000, "x": 320, "y": 450, "target": "#menu-item-1" }

ํ˜ธ๋ฒ„ ์ง€์†์‹œ๊ฐ„ ์ด๋ฒคํŠธ (์„œ๋ฒ„ ๊ณ„์‚ฐ)

{ "type": "hover_duration", "sessionId": "abc-123", "start": 1732501205000, "end": 1732501208000, "duration": 3000, "target": "#menu-item-1" }

5.๐Ÿงฉ ์˜ˆ์ƒ๋˜๋Š” ์ด์Šˆ

๐Ÿ”ฅ ๋ฌธ์ œโ€ฏ1 โ€“ ํด๋ฆญยทํ˜ธ๋ฒ„ ์ด๋ฒคํŠธ ํญ์ฃผ ์‹œ MongoDB ์„ฑ๋Šฅ ์ €ํ•˜

๋ฐฉ๋ฒ•์žฅ์ ๋‹จ์ 
insertMany๊ตฌํ˜„ ๊ฐ€์žฅ ๋‹จ์ˆœํญ์ฃผ ์‹œ write ์„ฑ๋Šฅ ์ €ํ•˜
BulkWrite๋Œ€๋Ÿ‰ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ์ตœ์ ํ™”์ฝ”๋“œ ๋ณต์žก
Redisโ€ฏQueueโ€ฏโ†’โ€ฏMongoโ€ฏBatchWrite๋ถ€ํ•˜ ์™„์ „ ๋ถ„์‚ฐRedis ์šด์˜ ํ•„์š”

ํ˜„์žฌ ํŒ๋‹จ: MVP ๋‹จ๊ณ„์—์„œ๋Š” insertMany ๋กœ ์‹œ์ž‘ํ•˜๊ณ , ์‹ค์ œ ํŠธ๋ž˜ํ”ฝ์—์„œ ๋ณ‘๋ชฉ์ด ๋ณด์ด๋ฉด Redisโ€ฏQueueโ€ฏโ†’โ€ฏBulkWrite ๋กœ ํ™•์žฅ ์˜ˆ์ •.

๐Ÿ”ฅ ๋ฌธ์ œโ€ฏ2 โ€“ ํ˜ธ๋ฒ„ ์ง€์†์‹œ๊ฐ„ ๊ณ„์‚ฐ ์œ„์น˜ (ํ”„๋ก ํŠธโ€ฏvsโ€ฏ์„œ๋ฒ„)

์œ„์น˜์žฅ์ ๋‹จ์ 
ํ”„๋ก ํŠธ๊ตฌํ˜„ ์‰ฌ์›€์‚ฌ์šฉ์ž์˜ ์ปดํ“จํ„ฐ ์„ฑ๋Šฅ/์ง€์—ฐ์— ์˜ํ–ฅ
์„œ๋ฒ„๋ฐ์ดํ„ฐ ์ •ํ™•๋„ ๋†’์Œ์„œ๋ฒ„์— ์ถ”๊ฐ€ ๋กœ์ง ํ•„์š”

ํ˜„์žฌ ํŒ๋‹จ: hoverโ€ฏstart/end ์ด๋ฒคํŠธ๋งŒ ๋ฐ›๊ณ , duration ์€ ์„œ๋ฒ„์—์„œ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉํ–ฅ์ด ์ ํ•ฉ.

๐Ÿ”ฅ ๋ฌธ์ œโ€ฏ3 โ€“ ๋Œ€์‹œ๋ณด๋“œ ์กฐํšŒ ์†๋„ ๊ฐœ์„ 

๋ฐฉ๋ฒ•์žฅ์ ๋‹จ์ 
Mongo ๋‹จ์ผ ์กฐํšŒ๋‹จ์ˆœ๋А๋ฆผ
Redis ์บ์‹ฑ๋น ๋ฆ„TTL ๊ด€๋ฆฌ ํ•„์š”
Materialized View์กฐํšŒ ์ตœ์ ํ™”์ค‘๋ณต ์ €์žฅ ์ฆ๊ฐ€

ํ˜„์žฌ ํŒ๋‹จ: ์ดˆ๊ธฐ์—๋Š” Mongo ๋‹จ์ผ ์กฐํšŒ ๋กœ ์‹œ์ž‘ํ•˜๊ณ , ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ์ค€๋น„๋˜๋ฉด Redis ์บ์‹ฑ ๋„์ž… ์˜ˆ์ •.

โ™ป๏ธ ์š”์•ฝ

  • MongoDash๋Š” ์›น ์‚ฌ์šฉ์ž ๋งˆ์šฐ์Šค ํ–‰๋™(ํด๋ฆญยทํ˜ธ๋ฒ„ยทํ˜ธ๋ฒ„ ์‹œ๊ฐ„)์„ ์ˆ˜์ง‘ยท๋ถ„์„ยท์‹œ๊ฐํ™”ํ•˜๋Š” ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.
  • ํ˜„์žฌ ์„ค๊ณ„ ๋‹จ๊ณ„์ด๋ฉฐ DB ๊ตฌ์กฐยทAPI ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถ• ์ค‘์ž…๋‹ˆ๋‹ค.
  • ์ด๋ฒคํŠธ ์Šคํ‚ค๋งˆ์™€ ์‹œ์Šคํ…œ ํ๋ฆ„์„ ๋ช…ํ™•ํžˆ ์ •์˜ํ–ˆ์œผ๋ฉฐ, ์„ฑ๋Šฅยทํ™•์žฅ์„ฑ์„ ์œ„ํ•œ ์—ฌ๋Ÿฌ ์˜ต์…˜์„ ๊ฒ€ํ† ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ–ฅํ›„ BulkWrite, Redisโ€ฏQueue, TTL ์ธ๋ฑ์Šค ๋“ฑ์„ ๋„์ž…ํ•ด ์„œ๋ฒ„ ํ™•์žฅ์„ฑ์„ ํ™•๋ณดํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค.

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

Last updated on