Skip to content

ShootPointer/ShootPointer_BE

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

1,030 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ€ ShootPointer Backend

ShootPointer๋Š” ๋†๊ตฌ ์˜์ƒ์„ ์—…๋กœ๋“œํ•˜๋ฉด ๊ฐœ์ธ ํ•˜์ด๋ผ์ดํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ƒ์„ฑ๋œ ๊ฒฐ๊ณผ๋ฅผ ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฒŒ์‹œ๊ธ€๊ณผ ๋žญํ‚น์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

  • ์ด ์„œ๋น„์Šค๊ฐ€ ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋Š”์ง€
  • ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ ๋ฐฑ์—”๋“œ ๋‚ด๋ถ€์—์„œ ์–ด๋–ค ๊ณ„์ธต๊ณผ ์ €์žฅ์†Œ๋ฅผ ๊ฑฐ์น˜๋Š”์ง€
  • ์™ธ๋ถ€ OpenCV ์„œ๋ฒ„์™€ ์–ด๋–ป๊ฒŒ ํ˜‘์—…ํ•˜๋Š”์ง€
  • ์ข‹์•„์š”/๋žญํ‚น/๊ฒ€์ƒ‰/์‹ค์‹œ๊ฐ„ ์ง„ํ–‰๋ฅ  ๊ฐ™์€ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€

๐Ÿ“š ๋ชฉ์ฐจ

๐Ÿš€ 1. ํ”„๋กœ์ ํŠธ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

1-1. ์„œ๋น„์Šค๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ

๋†๊ตฌ ์˜์ƒ ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉ์ž๋Š” ๋ณดํ†ต ๋‹ค์Œ ๋ฌธ์ œ๋ฅผ ๊ฒช์Šต๋‹ˆ๋‹ค.

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

ShootPointer๋Š” ์ด ๋ฌธ์ œ๋ฅผ ์•„๋ž˜ ํ๋ฆ„์œผ๋กœ ํ’€๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.

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

1-2. ์„œ๋น„์Šค ์ „์ฒด ๋น„์ฆˆ๋‹ˆ์Šค ํ๋ฆ„

flowchart LR
    A["์นด์นด์˜ค ๋กœ๊ทธ์ธ"] --> B["JWT ์ธ์ฆ"]
    B --> C["๋“ฑ๋ฒˆํ˜ธ ๋“ฑ๋ก"]
    C --> D["์˜์ƒ ์—…๋กœ๋“œ์šฉ ์„œ๋ช… URL ๋ฐœ๊ธ‰"]
    D --> E["OpenCV ์„œ๋ฒ„๋กœ ์˜์ƒ ์—…๋กœ๋“œ"]
    E --> F["Redis Pub/Sub ์ง„ํ–‰๋ฅ  ๋ฐœํ–‰"]
    F --> G["SSE๋กœ ํด๋ผ์ด์–ธํŠธ์— ์‹ค์‹œ๊ฐ„ ์ „๋‹ฌ"]
    E --> H["ํ•˜์ด๋ผ์ดํŠธ ๊ฒฐ๊ณผ Webhook"]
    H --> I["Highlight ์ €์žฅ"]
    I --> J["๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ"]
    J --> K["๋Œ“๊ธ€ / ์ข‹์•„์š” / ๊ฒ€์ƒ‰"]
    K --> L["๋žญํ‚น ์กฐํšŒ ๋ฐ ์ง‘๊ณ„"]
Loading

1-3. ์ด ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฑ์—”๋“œ ์—ญ๋Ÿ‰

  • OAuth2 ์†Œ์…œ ๋กœ๊ทธ์ธ๊ณผ JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ/์ธ๊ฐ€
  • ์™ธ๋ถ€ OpenCV ์„œ๋ฒ„์™€์˜ HTTP ์—ฐ๋™
  • Redis Pub/Sub + SSE ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ ์ƒํƒœ ์ „๋‹ฌ
  • PostgreSQL / Redis / Elasticsearch / MongoDB๋ฅผ ์—ญํ• ๋ณ„๋กœ ๋ถ„๋ฆฌํ•œ ์„ค๊ณ„
  • JPA ์ค‘์‹ฌ์˜ ๋„๋ฉ”์ธ ๋กœ์ง๊ณผ Query ๋ถ„๋ฆฌ
  • ์ข‹์•„์š” ๋™์‹œ์„ฑ ์ œ์–ด์™€ 10,000๊ฑด ๋™์‹œ์„ฑ ํ…Œ์ŠคํŠธ
  • Docker Compose์™€ Jenkins ๊ธฐ๋ฐ˜ ์šด์˜ ์ž๋™ํ™”
  • Spring Modulith ๊ธฐ๋ฐ˜ ๋ชจ๋“ˆ ๋ถ„๋ฆฌ ๋ฆฌํŒฉํ„ฐ๋ง

๐Ÿ—บ๏ธ 2. ์„œ๋น„์Šค ์ „์ฒด ํ๋ฆ„

2-1. ์‹œ์Šคํ…œ ์ปจํ…์ŠคํŠธ

flowchart LR
    Client["Client"]
    Api["API Server\nSpring Boot"]
    Batch["Batch Server\n๋ถ„๋ฆฌ ๊ตฌ์กฐ ์„ค๊ณ„"]
    Kakao["Kakao OAuth"]
    OpenCV["OpenCV Server"]
    Postgres["PostgreSQL"]
    Redis["Redis"]
    ES["Elasticsearch"]
    Mongo["MongoDB"]
    Kibana["Kibana"]

    Client --> Api
    Api --> Kakao
    Api --> Postgres
    Api --> Redis
    Api --> ES
    Api --> Mongo
    Api --> OpenCV

    OpenCV -. "progress channel publish" .-> Redis
    Batch -. "aggregation / snapshot" .-> Mongo
    Batch -. "batch query" .-> Postgres
    Kibana --> ES
Loading

2-2. ํ•ต์‹ฌ ์ €์žฅ์†Œ๋ณ„ ์—ญํ• 

์ €์žฅ์†Œ ์—ญํ• 
PostgreSQL ํšŒ์›, ๋“ฑ๋ฒˆํ˜ธ, ํ•˜์ด๋ผ์ดํŠธ, ๊ฒŒ์‹œ๊ธ€, ๋Œ“๊ธ€, ์ข‹์•„์š” ๋“ฑ ์šด์˜ ๋ฐ์ดํ„ฐ ์ €์žฅ
Redis Refresh Token, ์—…๋กœ๋“œ Job TTL, ๋žญํ‚น ZSet, OpenCV ์ง„ํ–‰๋ฅ  Pub/Sub
Elasticsearch ๊ฒŒ์‹œ๊ธ€ ๊ฒ€์ƒ‰๊ณผ ์ž๋™์™„์„ฑ
MongoDB ๊ธฐ๊ฐ„๋ณ„ ๋žญํ‚น ์Šค๋ƒ…์ƒท ๋ฌธ์„œ ์ €์žฅ

2-3. Redis ์‚ฌ์šฉ ๋ชฉ์  ์„ธ๋ถ„ํ™”

์ด ํ”„๋กœ์ ํŠธ์—์„œ Redis๋Š” ๋‹จ์ˆœ ์บ์‹œ๊ฐ€ ์•„๋‹ˆ๋ผ 4๊ฐ€์ง€ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋ชฉ์  ์‚ฌ์šฉ ๋ฐฉ์‹
์ธ์ฆ refresh:{email} ํ˜•ํƒœ๋กœ Refresh Token ์ €์žฅ
์—…๋กœ๋“œ ์ถ”์  prefix + memberId์— jobId ์ €์žฅ
์‹ค์‹œ๊ฐ„ ์ด๋ฒคํŠธ OpenCV ์ง„ํ–‰๋ฅ  Pub/Sub ์ฑ„๋„ ๊ตฌ๋…
๋žญํ‚น ZSet ๊ธฐ๋ฐ˜ ์ฃผ๊ฐ„/์›”๊ฐ„ ํ˜„์žฌ ๋žญํ‚น ์ €์žฅ

2-4. OpenCV ์—ฐ๋™์ด ์ค‘์š”ํ•œ ์ด์œ 

์ด ๋ฐฑ์—”๋“œ๋Š” ํŒŒ์ผ์„ ์ง์ ‘ ๋ถ„์„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋Œ€์‹  OpenCV ์„œ๋ฒ„์™€ ์—ญํ• ์„ ๋ถ„๋ฆฌํ•ด ์•„๋ž˜์ฒ˜๋Ÿผ ํ˜‘์—…ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฐฑ์—”๋“œ๋Š” ์‚ฌ์šฉ์ž ์ธ์ฆ, ์—…๋กœ๋“œ ๊ถŒํ•œ ๋ฐœ๊ธ‰, ๊ฒฐ๊ณผ ์ €์žฅ, ์ง„ํ–‰๋ฅ  ์ „๋‹ฌ์„ ๋‹ด๋‹น
  • OpenCV ์„œ๋ฒ„๋Š” ์˜์ƒ ์ฒ˜๋ฆฌ, ๊ฐœ์ธ ์‹๋ณ„, ํ•˜์ด๋ผ์ดํŠธ ์ƒ์„ฑ, ์ง„ํ–‰๋ฅ  ๋ฐœํ–‰์„ ๋‹ด๋‹น

์ฆ‰, ์ด ์„œ๋น„์Šค์˜ ํ•ต์‹ฌ์€ "๋ฏธ๋””์–ด ์ฒ˜๋ฆฌ ์ž์ฒด"๋ณด๋‹ค "๋ฏธ๋””์–ด ์ฒ˜๋ฆฌ ์„œ๋ฒ„์™€ ์•ˆ์ „ํ•˜๊ฒŒ ํ˜‘์—…ํ•˜๋Š” ๋ฐฑ์—”๋“œ ์„ค๊ณ„"์— ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿงฐ 3. ๊ธฐ์ˆ  ์Šคํƒ๊ณผ ์ €์žฅ์†Œ ์—ญํ• 

3-1. ๊ธฐ์ˆ  ์Šคํƒ

๋ถ„๋ฅ˜ ๊ธฐ์ˆ 
Language Java 21
Framework Spring Boot 3.4.5
Security Spring Security, JWT, OAuth2 Client
ORM Spring Data JPA
DB PostgreSQL
Cache / Messaging Redis, Redisson
Search Elasticsearch
Document DB MongoDB
Async / Client WebClient, RestTemplate, SSE
Batch Spring Batch
Docs Swagger / OpenAPI
Test JUnit5, Spring Boot Test, Testcontainers
Infra Docker, Docker Compose, Jenkins, Azure

3-2. ์™œ ์ €์žฅ์†Œ๋ฅผ ๋‚˜๋ˆด๋Š”๊ฐ€

  • ์ •ํ•ฉ์„ฑ์ด ์ค‘์š”ํ•œ ์šด์˜ ๋ฐ์ดํ„ฐ๋Š” PostgreSQL์— ์ €์žฅ
  • ๋น ๋ฅธ ํ† ํฐ ์ €์žฅ๊ณผ ์ด๋ฒคํŠธ ๋ธŒ๋กœ์ปค ์—ญํ• ์€ Redis์— ์œ„์ž„
  • ๊ฒŒ์‹œ๊ธ€ ๊ฒ€์ƒ‰ ํ’ˆ์งˆ์€ Elasticsearch๋กœ ๋ถ„๋ฆฌ
  • ๊ณผ๊ฑฐ ๊ธฐ๊ฐ„ ๋žญํ‚น ์Šค๋ƒ…์ƒท์€ MongoDB์— ์ €์žฅ

์ฆ‰, ํ•œ DB์— ๋‹ค ๋ชฐ์•„๋„ฃ์ง€ ์•Š๊ณ  "๊ฐ ์ €์žฅ์†Œ์˜ ๊ฐ•์ "์— ๋งž๊ฒŒ ์—ญํ• ์„ ๋ถ„๋ฆฌํ•œ ์„ค๊ณ„์ž…๋‹ˆ๋‹ค.

๐Ÿ—๏ธ 4. ๋ฐฑ์—”๋“œ ์ฒ˜๋ฆฌ ๊ตฌ์กฐ

4-1. ๊ณตํ†ต ์ฒ˜๋ฆฌ ๊ณ„์ธต

๋งŽ์€ ๋„๋ฉ”์ธ ๊ธฐ๋Šฅ์ด ์•„๋ž˜ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

flowchart LR
    A["Controller"] --> B["Service"]
    B --> C["Manager"]
    C --> D["Helper"]
    D --> E["Util / Validation / Mapper"]
    E --> F["Repository"]
    F --> G["DB / External System"]
Loading

4-2. ๊ฐ ๊ณ„์ธต์˜ ์—ญํ• 

๊ณ„์ธต ์—ญํ• 
Controller HTTP ์š”์ฒญ/์‘๋‹ต, ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆ˜์ง‘
Service ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘์ , ์œ ์ฆˆ์ผ€์ด์Šค ์œ„์ž„
Manager ์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค ํ๋ฆ„ ์กฐํ•ฉ
Helper Validation / Util ์กฐํ•ฉ์„ ์œ„ํ•œ ์ค‘๊ฐ„ ๊ณ„์ธต
Util / Validation / Mapper ์กฐํšŒ, ์ €์žฅ, ๊ฒ€์ฆ, DTO-Entity ๋ณ€ํ™˜
Repository DB ์ ‘๊ทผ

์ด ๊ตฌ์กฐ๋Š” ๋‹ค์†Œ ๋ ˆ๊ฑฐ์‹œ์Šค๋Ÿฝ์ง€๋งŒ, ์ฑ…์ž„์„ ์ชผ๊ฐœ์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์ข‹๊ณ , ๊ฐ ๋‹จ์œ„๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ๊ต์ฒดํ•˜๊ธฐ ์‰ฝ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

4-3. ๊ณตํ†ต ์‘๋‹ต ๊ตฌ์กฐ

๋ชจ๋“  API๋Š” ๊ณตํ†ต ์‘๋‹ต ํฌ๋งท์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ์„ฑ๊ณต ์‹œ: status, success=true, data
  • ์‹คํŒจ ์‹œ: status, success=false, error

์ด๋ฅผ ํ†ตํ•ด ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ๋„๋ฉ”์ธ๋ณ„๋กœ ์‘๋‹ต ํ˜•์‹์„ ๋‹ค๋ฅด๊ฒŒ ํŒŒ์‹ฑํ•  ํ•„์š”๋ฅผ ์ค„์˜€์Šต๋‹ˆ๋‹ค.

4-4. ๊ณตํ†ต ์˜ˆ์™ธ ์ฒ˜๋ฆฌ

GlobalExceptionHandler๊ฐ€ ๋‹ค์Œ ์˜ˆ์™ธ๋ฅผ ์ผ๊ด€๋œ ์‘๋‹ต์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • ์กด์žฌํ•˜์ง€ ์•Š๋Š” endpoint
  • CustomException
  • ๊ทธ ์™ธ ๊ธฐ๋ณธ ์˜ˆ์™ธ

4-5. ๊ณตํ†ต ์—”ํ‹ฐํ‹ฐ ์ •์ฑ…

๋Œ€๋ถ€๋ถ„์˜ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ณตํ†ต ๋ฒ ์ด์Šค ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • created_at, modified_at ์ž๋™ ๊ด€๋ฆฌ
  • is_deleted, deleted_at ๊ธฐ๋ฐ˜ ๋…ผ๋ฆฌ ์‚ญ์ œ

ํŠนํžˆ ๊ฒŒ์‹œ๊ธ€๊ณผ ๋Œ“๊ธ€์€ ๋…ผ๋ฆฌ ์‚ญ์ œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • PostEntity๋Š” @SQLRestriction("is_deleted = false")
  • Comment๋„ ๋™์ผํ•œ ๋…ผ๋ฆฌ ์‚ญ์ œ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉ

์ฆ‰, ์‚ญ์ œ ์š”์ฒญ์ด ์™€๋„ ์‹ค์ œ row๋ฅผ ๋ฐ”๋กœ ์—†์• ๋Š” ๋Œ€์‹  soft delete๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

4-6. ๊ฐœ์ธ์ •๋ณด ์•”ํ˜ธํ™”

ํšŒ์› ์ด๋ฆ„๊ณผ ์ด๋ฉ”์ผ์€ DB ์ปฌ๋Ÿผ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ํ†ตํ•ด ์•”ํ˜ธํ™” ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

  • member_name
  • email

์ฆ‰, ๋ฏผ๊ฐํ•œ PII๋ฅผ ํ‰๋ฌธ์œผ๋กœ ์ง์ ‘ ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

4-7. AOP ํ™œ์šฉ

๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋ฅผ ์œ„ํ•ด AOP๋„ ์ผ๋ถ€ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • @CustomLog ๊ธฐ๋ฐ˜ ๋ฉ”์„œ๋“œ ๋กœ๊น…
  • DistributedLockAspect ๊ธฐ๋ฐ˜ ๋ถ„์‚ฐ๋ฝ ํ™•์žฅ ํฌ์ธํŠธ

๋‹ค๋งŒ ํ˜„์žฌ "์ข‹์•„์š” ์ •ํ•ฉ์„ฑ"์˜ ์ตœ์ข… ๊ตฌํ˜„์€ ๋ถ„์‚ฐ๋ฝ์ด ์•„๋‹ˆ๋ผ DB ๋น„๊ด€์  ๋ฝ์„ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ” 5. ์ƒ์„ธ ๊ธฐ๋Šฅ ์„ค๋ช…

๐Ÿ” 5-1. ์ธ์ฆ / ํšŒ์›

๊ด€๋ จ API

Method Endpoint ํ˜ธ์ถœ์ž ์„ค๋ช…
GET /kakao/callback Kakao redirect ์ธ๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ ํ›„ JWT ๋ฐœ๊ธ‰
GET /member/me ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž ๋‚ด ์ •๋ณด ์กฐํšŒ
DELETE /kakao ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž ํšŒ์› ํƒˆํ‡ด
PUT /agree/highlight ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž ํ•˜์ด๋ผ์ดํŠธ ์ง‘๊ณ„ ๋™์˜
GET /admin/token ๋‚ด๋ถ€/ํ…Œ์ŠคํŠธ ๊ด€๋ฆฌ์ž์šฉ ํ† ํฐ ๋ฐœ๊ธ‰
POST /admin/token/check ๋‚ด๋ถ€/ํ…Œ์ŠคํŠธ ํ† ํฐ์œผ๋กœ ํšŒ์› ๋™๊ธฐํ™”
GET /admin/token/refresh/{email} ๋‚ด๋ถ€/ํ…Œ์ŠคํŠธ Refresh Token ์กฐํšŒ

5-1-1. ์นด์นด์˜ค ๋กœ๊ทธ์ธ๊ณผ JWT ๋ฐœ๊ธ‰ ํ๋ฆ„

sequenceDiagram
    participant Client
    participant Kakao
    participant Controller as MemberCommandController
    participant Service as MemberCommandService
    participant KakaoService
    participant Manager as MemberManager
    participant DB as PostgreSQL
    participant Redis

    Client->>Kakao: ์นด์นด์˜ค ๋กœ๊ทธ์ธ
    Kakao-->>Client: authorization code
    Client->>Controller: GET /kakao/callback?code=...
    Controller->>Service: processKakaoLogin(request)
    Service->>Manager: callback ๊ฒ€์ฆ
    Service->>KakaoService: ์‚ฌ์šฉ์ž ์ •๋ณด ์š”์ฒญ
    KakaoService->>Kakao: access token ์š”์ฒญ
    KakaoService->>Kakao: user info ์š”์ฒญ
    Service->>Manager: ํšŒ์› ์กฐํšŒ ๋˜๋Š” ์‹ ๊ทœ ์ƒ์„ฑ
    Manager->>DB: member find/save
    Service->>Redis: Refresh Token ์ €์žฅ
    Service-->>Controller: KakaoDTO(access/refresh ํฌํ•จ)
    Controller-->>Client: ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‘๋‹ต
Loading

5-1-2. ๋‚ด๋ถ€ ๋™์ž‘ ์„ค๋ช…

  1. /kakao/callback์ด ํ˜ธ์ถœ๋˜๋ฉด MemberCommandServiceImpl.processKakaoLogin์ด ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.
  2. ์š”์ฒญ์—์„œ code๋ฅผ ์ถ”์ถœํ•˜๊ณ , KakaoServiceImpl์ด ์‹ค์ œ ์นด์นด์˜ค API ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  3. KakaoApiHelperImpl์ด
    • ํ† ํฐ endpoint๋กœ access token ์š”์ฒญ
    • ์‚ฌ์šฉ์ž ์ •๋ณด endpoint๋กœ ํ”„๋กœํ•„ ์กฐํšŒ ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  4. MemberManager๋Š” ์ด๋ฉ”์ผ ๊ธฐ์ค€์œผ๋กœ ํšŒ์›์„ ์ฐพ๊ณ , ์—†์œผ๋ฉด ์‹ ๊ทœ ํšŒ์›์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  5. TokenServiceImpl์ด Access Token๊ณผ Refresh Token์„ ๋ฐœ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.
  6. Refresh Token์€ Redis์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  7. ์ตœ์ข…์ ์œผ๋กœ KakaoDTO์— access / refresh token์„ ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

5-1-3. ์ธ์ฆ๋œ ์š”์ฒญ์ด ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฐฉ์‹

sequenceDiagram
    participant Client
    participant Filter as JwtAuthenticationFilter
    participant Jwt as JwtHandler/JwtUtil
    participant UDS as CustomUserDetailsService
    participant MQS as MemberQueryService
    participant DB as PostgreSQL
    participant SC as SecurityContext
    participant Controller

    Client->>Filter: API ์š”์ฒญ + Bearer Token
    Filter->>Jwt: token resolve / validate
    Jwt->>Jwt: email ์ถ”์ถœ
    Filter->>UDS: loadUserByUsername(email)
    UDS->>MQS: findByEmail(email)
    MQS->>DB: member ์กฐํšŒ
    UDS-->>Filter: CustomUserDetails ๋ฐ˜ํ™˜
    Filter->>SC: Authentication ์ €์žฅ
    SC-->>Controller: ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ ‘๊ทผ ๊ฐ€๋Šฅ
Loading

5-1-4. /member/me ๋™์ž‘

/member/me๋Š” ๋‹จ์ˆœ ํšŒ์› row ์กฐํšŒ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
ํšŒ์› ๊ธฐ๋ณธ ์ •๋ณด + ๋“ฑ๋ฒˆํ˜ธ + ์Š› ํ†ต๊ณ„ + ํ•˜์ด๋ผ์ดํŠธ ๊ฐœ์ˆ˜๋ฅผ ์กฐํ•ฉํ•ด ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.

flowchart LR
    A["/member/me ์š”์ฒญ"] --> B["SecurityUtils.getCurrentMember()"]
    B --> C["MemberManager.getMemberInfo(memberId)"]
    C --> D["Member ์กฐํšŒ"]
    C --> E["ํšŒ์›-๋“ฑ๋ฒˆํ˜ธ ์กฐํšŒ"]
    C --> F["Highlight 2์  ํ•ฉ ์กฐํšŒ"]
    C --> G["Highlight 3์  ํ•ฉ ์กฐํšŒ"]
    C --> H["Highlight ๊ฐœ์ˆ˜ ์กฐํšŒ"]
    D --> I["MemberResponseDto ์กฐํ•ฉ"]
    E --> I
    F --> I
    G --> I
    H --> I
Loading

5-1-5. ํšŒ์› ํƒˆํ‡ด์™€ ์ง‘๊ณ„ ๋™์˜

  • ํšŒ์› ํƒˆํ‡ด
    • ํ˜„์žฌ ์ธ์ฆ๋œ ํšŒ์›์ธ์ง€ ๊ฒ€์ฆ
    • DB์—์„œ ํšŒ์› ์‚ญ์ œ
    • Redis Refresh Token ์‚ญ์ œ
  • ์ง‘๊ณ„ ๋™์˜
    • Member.agree() ๋„๋ฉ”์ธ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
    • ์ด๋ฏธ ๋™์˜ํ–ˆ๋‹ค๋ฉด ์˜ˆ์™ธ ์ฒ˜๋ฆฌ

์ฆ‰, ๋‹จ์ˆœ flag ์ˆ˜์ •์ด ์•„๋‹ˆ๋ผ ๋„๋ฉ”์ธ ์ƒํƒœ ๋ณ€๊ฒฝ์œผ๋กœ ์ทจ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿท๏ธ 5-2. ๋“ฑ๋ฒˆํ˜ธ ๋“ฑ๋ก

๊ด€๋ จ API

Method Endpoint ์ธ์ฆ ์„ค๋ช…
POST /api/backNumber ์‚ฌ์šฉ์ž JWT ๋“ฑ๋ฒˆํ˜ธ์™€ ๋“ฑ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€ ๋“ฑ๋ก

5-2-1. ๋“ฑ๋ฒˆํ˜ธ ๋“ฑ๋ก ํ๋ฆ„

sequenceDiagram
    participant Client
    participant Controller as BackNumberController
    participant Service as BackNumberCommandService
    participant Manager as BackNumberManager
    participant BackNumberHelper
    participant MemberBackNumberHelper
    participant OpenCV as OpenCVClient
    participant DB as PostgreSQL

    Client->>Controller: multipart ์š”์ฒญ(backNumberRequestDto, image)
    Controller->>Service: create(member, backNumberEntity, image)
    Service->>Manager: create(...)
    Manager->>BackNumberHelper: ๋“ฑ๋ฒˆํ˜ธ ์กฐํšŒ ๋˜๋Š” ์ƒ์„ฑ
    BackNumberHelper->>DB: back_number ์ €์žฅ/์กฐํšŒ
    Manager->>MemberBackNumberHelper: ํšŒ์›-๋“ฑ๋ฒˆํ˜ธ ๋งคํ•‘ ์กฐํšŒ ๋˜๋Š” ์ƒ์„ฑ
    MemberBackNumberHelper->>DB: member_back_number ์ €์žฅ/์กฐํšŒ
    Manager->>OpenCV: ๋“ฑ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€ ์ „์†ก
    OpenCV-->>Manager: ๊ฒ€์ฆ ์‘๋‹ต
    Manager-->>Controller: ๋“ฑ๋ก๋œ ๋“ฑ๋ฒˆํ˜ธ ๋ฐ˜ํ™˜
Loading

5-2-2. ํ•ต์‹ฌ ํฌ์ธํŠธ

  1. ๋“ฑ๋ฒˆํ˜ธ ์ž์ฒด๋Š” back_number ๋งˆ์Šคํ„ฐ ํ…Œ์ด๋ธ”์—์„œ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  2. ์‚ฌ์šฉ์ž์™€ ๋“ฑ๋ฒˆํ˜ธ์˜ ๊ด€๊ณ„๋Š” member_back_number ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  3. ์ฆ‰, "๋“ฑ๋ฒˆํ˜ธ ๊ฐ’"๊ณผ "๋ˆ„๊ฐ€ ๊ทธ ๋“ฑ๋ฒˆํ˜ธ๋ฅผ ์“ฐ๋Š”๊ฐ€"๋ฅผ ๋ถ„๋ฆฌํ•œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
  4. ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์—์„œ OpenCV ์„œ๋ฒ„์— ๋“ฑ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€์™€ ๋“ฑ๋ฒˆํ˜ธ ๊ฐ’์„ ํ•จ๊ป˜ ์ „๋‹ฌํ•ด ์ดํ›„ ๊ฐœ์ธ ํ•˜์ด๋ผ์ดํŠธ ์ƒ์„ฑ์˜ ๊ธฐ์ค€ ์ •๋ณด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

5-2-3. OpenCV ํ˜ธ์ถœ ๋ฐฉ์‹

OpenCVClientImpl.sendBackNumberInformation์€ ์•„๋ž˜ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • multipart/form-data POST
  • ํ—ค๋”์— X-Member-Id ์ „๋‹ฌ
  • body์— image, backNumber ํฌํ•จ
  • ์ตœ๋Œ€ 15์ดˆ timeout
  • IOException, TimeoutException, WebClientRequestException ๊ณ„์—ด์€ ์žฌ์‹œ๋„
  • ์‘๋‹ต์ด ์‹คํŒจ๊ฑฐ๋‚˜ ๋“ฑ๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์™ธ ์ฒ˜๋ฆฌ

์ฆ‰, ๋‹จ์ˆœ ์™ธ๋ถ€ API ํ˜ธ์ถœ์ด ์•„๋‹ˆ๋ผ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜์™€ ๋„๋ฉ”์ธ ์˜ค๋ฅ˜๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

๐Ÿ”‘ 5-3. ์—…๋กœ๋“œ์šฉ Pre-signed URL ๋ฐœ๊ธ‰

๊ด€๋ จ API

Method Endpoint ์ธ์ฆ ์„ค๋ช…
POST /api/pre-signed ์‚ฌ์šฉ์ž JWT OpenCV ์—…๋กœ๋“œ์šฉ ์„œ๋ช… URL ๋ฐœ๊ธ‰

5-3-1. ์™œ ์ด ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ๊ฐ€

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ž„์˜๋กœ OpenCV ์—…๋กœ๋“œ endpoint์— ๋ฐ”๋กœ ํŒŒ์ผ์„ ๋˜์ง€๋ฉด ๋‹ค์Œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.

  • ๋ˆ„๊ฐ€ ์–ด๋–ค ๊ถŒํ•œ์œผ๋กœ ์—…๋กœ๋“œํ•˜๋Š”์ง€ ๋ฐฑ์—”๋“œ๊ฐ€ ํ†ต์ œํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
  • ์—…๋กœ๋“œ ์ž‘์—…๊ณผ ์‚ฌ์šฉ์ž/์ž‘์—… ID ๋งคํ•‘์„ ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
  • ์ง„ํ–‰๋ฅ  ๊ตฌ๋…๊ณผ ๊ฒฐ๊ณผ ์กฐํšŒ๋ฅผ job ๋‹จ์œ„๋กœ ์—ฐ๊ฒฐํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

๊ทธ๋ž˜์„œ ์—…๋กœ๋“œ ์ „ ๋‹จ๊ณ„์—์„œ ๋ฐฑ์—”๋“œ๊ฐ€ "์งง์€ ์ˆ˜๋ช…์˜ ์—…๋กœ๋“œ ๊ถŒํ•œ"์„ ๋ฐœ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.

5-3-2. ๋ฐœ๊ธ‰ ํ๋ฆ„

sequenceDiagram
    participant Client
    participant Controller as PresignedUrlController
    participant Service as PresignedUrlService
    participant Validator as FileValidator
    participant Encryptor as AesGcmEncryptor
    participant Redis
    participant OpenCV

    Client->>Controller: POST /api/pre-signed(file metadata)
    Controller->>Service: createPresignedUrl(memberId, request)
    Service->>Validator: ํŒŒ์ผ ํฌ๊ธฐ/ํ™•์žฅ์ž ๊ฒ€์ฆ
    Service->>Service: jobId ์ƒ์„ฑ
    Service->>Encryptor: expires:memberId:jobId ์•”ํ˜ธํ™”
    Encryptor-->>Service: signature
    Service->>Redis: memberId ๊ธฐ๋ฐ˜ jobId TTL ์ €์žฅ
    Service-->>Controller: preSignedUrl + signature + jobId
    Controller-->>Client: ์—…๋กœ๋“œ์šฉ URL ๋ฐ˜ํ™˜
    Client->>OpenCV: signed URL๋กœ ์˜์ƒ ์—…๋กœ๋“œ
Loading

5-3-3. ๋‚ด๋ถ€ ๋™์ž‘ ์„ค๋ช…

  1. ์š”์ฒญ์ด ์˜ค๋ฉด SecurityUtils๋กœ ํ˜„์žฌ ํšŒ์› ID๋ฅผ ๊ตฌํ•ฉ๋‹ˆ๋‹ค.
  2. PresignedUrlService๋Š” ๋‚œ์ˆ˜ ๊ธฐ๋ฐ˜ jobId๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  3. ๋งŒ๋ฃŒ ์‹œ๊ฐ๊ณผ memberId, jobId๋ฅผ ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด๋กœ ๋ฌถ์Šต๋‹ˆ๋‹ค.
  4. AesGcmEncryptor๊ฐ€ ์ด ๋ฌธ์ž์—ด์„ AES-GCM์œผ๋กœ ์•”ํ˜ธํ™”ํ•ฉ๋‹ˆ๋‹ค.
  5. ์•”ํ˜ธ๋ฌธ์„ query parameter๋กœ ๋„ฃ์€ OpenCV ์—…๋กœ๋“œ URL์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  6. ๊ฐ™์€ ์‹œ์ ์— Redis์— memberId -> jobId๋ฅผ TTL๊ณผ ํ•จ๊ป˜ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  7. ํด๋ผ์ด์–ธํŠธ๋Š” ์ด URL๋กœ ์ง์ ‘ ์—…๋กœ๋“œํ•˜๊ณ , ์ดํ›„ ๊ฐ™์€ jobId๋กœ ์ง„ํ–‰๋ฅ ๊ณผ ๊ฒฐ๊ณผ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.

5-3-4. ๋ณด์•ˆ ํฌ์ธํŠธ

  • ์„œ๋ช… ์›๋ฌธ: expires:memberId:jobId
  • ์•”ํ˜ธํ™” ๋ฐฉ์‹: AES-GCM
  • IV๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ๋žœ๋ค ์ƒ์„ฑ
  • ๊ฒฐ๊ณผ๋Š” URL-safe Base64 ๋ฌธ์ž์—ด
  • ํŒŒ์ผ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋Š” ์‚ฌ์ „ ๊ฒ€์ฆ
    • ํ™•์žฅ์ž: .mp4
    • ํฌ๊ธฐ: ์„ค์ •๊ฐ’ ๊ธฐ๋ฐ˜ ์ œํ•œ

์ฆ‰, ๋‹จ์ˆœ ํ† ํฐ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ผ "๋งŒ๋ฃŒ ์‹œ๊ฐ„๊ณผ ์‚ฌ์šฉ์ž/์ž‘์—… ์‹๋ณ„์ž๋ฅผ ๋ฌถ์€ ์„œ๋ช…"์„ ๋ฐœ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.

5-3-5. ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ

flowchart TD
    A["memberId"] --> D["expires:memberId:jobId"]
    B["jobId"] --> D
    C["expires"] --> D
    D --> E["AES-GCM Encrypt"]
    E --> F["signature"]
    F --> G["OpenCV upload URL"]
Loading

๐Ÿ“ก 5-4. ์ง„ํ–‰๋ฅ  ์ŠคํŠธ๋ฆฌ๋ฐ๊ณผ ํ•˜์ด๋ผ์ดํŠธ ๊ฒฐ๊ณผ ์ˆ˜์‹ 

๊ด€๋ จ API

Method Endpoint ์ธ์ฆ ์„ค๋ช…
GET /api/progress/subscribe?jobId=... ์‚ฌ์šฉ์ž JWT SSE ๊ตฌ๋…
GET /api/progress?jobId=... ์‚ฌ์šฉ์ž JWT ์ตœ์‹  ์ง„ํ–‰๋ฅ  polling ์กฐํšŒ
POST /api/highlight/upload-result OpenCV ์‹œ์Šคํ…œ ํ˜ธ์ถœ ์™„์„ฑ๋œ ํ•˜์ด๋ผ์ดํŠธ ๊ฒฐ๊ณผ ์ €์žฅ

5-4-1. ์‹ค์‹œ๊ฐ„ ์ง„ํ–‰๋ฅ  ํ๋ฆ„

sequenceDiagram
    participant Client
    participant API as API Server
    participant Redis
    participant OpenCV

    Client->>API: GET /api/progress/subscribe?jobId=...
    API-->>Client: SSE emitter ์—ฐ๊ฒฐ
    OpenCV->>Redis: opencv-progress-upload:{jobId} publish
    OpenCV->>Redis: opencv-progress-highlight:{jobId} publish
    API->>Redis: channel subscribe
    Redis-->>API: ์ง„ํ–‰๋ฅ  payload ์ „๋‹ฌ
    API-->>Client: SSE event ์ „์†ก
Loading

5-4-2. ๋‚ด๋ถ€ ์ปดํฌ๋„ŒํŠธ ํ๋ฆ„

flowchart LR
    A["Redis Message"] --> B["ProgressSubscriber"]
    B --> C["ProgressValidator"]
    C --> D["ProgressSseEmitter.sendToClient"]
    D --> E["eventCache ์ €์žฅ"]
    D --> F["active emitter ์žˆ์œผ๋ฉด ์ฆ‰์‹œ ์ „์†ก"]
    E --> G["์žฌ์—ฐ๊ฒฐ ์‹œ Last-Event-ID ๊ธฐ๋ฐ˜ replay"]
Loading

5-4-3. ์™œ SSE๋ฅผ ์„ ํƒํ–ˆ๋Š”๊ฐ€

์ด ๊ธฐ๋Šฅ์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—…๋กœ๋“œ์™€ ํ•˜์ด๋ผ์ดํŠธ ์ƒ์„ฑ ์ƒํƒœ๋ฅผ ๊ณ„์† ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
Polling๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ์š”์ฒญ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ด ํ”„๋กœ์ ํŠธ๋Š” ๋‹ค์Œ ๋‘ ๊ฒฝ๋กœ๋ฅผ ๋ชจ๋‘ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • ๊ธฐ๋ณธ ๊ฒฝ๋กœ: SSE
  • fallback ๊ฒฝ๋กœ: /api/progress?jobId=...

์ฆ‰, ์‹ค์‹œ๊ฐ„์„ฑ์€ SSE๋กœ ํ™•๋ณดํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ ์ œ์•ฝ์ด ์žˆ๋Š” ๊ฒฝ์šฐ polling์œผ๋กœ๋„ ๋Œ€์‘ํ•ฉ๋‹ˆ๋‹ค.

5-4-4. ProgressSseEmitter์˜ ์—ญํ• 

์ด ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹จ์ˆœ emitter ์ €์žฅ์†Œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

  • memberId:jobId ์กฐํ•ฉ์œผ๋กœ emitter ๊ด€๋ฆฌ
  • ์ตœ๊ทผ ์ด๋ฒคํŠธ๋ฅผ deque์— ์บ์‹œ
  • Last-Event-ID๊ฐ€ ์˜ค๋ฉด ๋ˆ„๋ฝ ์ด๋ฒคํŠธ replay
  • TTL ์ดํ›„ ์˜ค๋ž˜๋œ ์ด๋ฒคํŠธ ์ •๋ฆฌ
  • ์ตœ์‹  ์ง„ํ–‰๋ฅ ์„ ๋ณ„๋„ map์— ์ €์žฅํ•ด polling fallback ์ง€์›

์ฆ‰, "์ง€๊ธˆ ์—ฐ๊ฒฐ๋œ ์‚ฌ์šฉ์ž์—๊ฒŒ๋งŒ ๋ณด๋‚ด๊ธฐ"๊ฐ€ ์•„๋‹ˆ๋ผ "์ž ๊น ๋Š๊ฒผ๋‹ค๊ฐ€ ๋‹ค์‹œ ์—ฐ๊ฒฐ๋œ ์‚ฌ์šฉ์ž๋„ ๋†“์น˜์ง€ ์•Š๋„๋ก" ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

5-4-5. OpenCV ๊ฒฐ๊ณผ ์ €์žฅ ํ๋ฆ„

sequenceDiagram
    participant OpenCV
    participant Controller as HighlightCommandController
    participant Service as HighlightCommandService
    participant Manager as HighlightManager
    participant Factory as HighlightFactory
    participant DB as PostgreSQL

    OpenCV->>Controller: POST /api/highlight/upload-result
    Controller->>Service: uploadHighlights(request, memberId)
    Service->>Manager: saveHighlights(...)
    Manager->>DB: Member ์กฐํšŒ
    Manager->>DB: Member์˜ BackNumber ์กฐํšŒ
    Manager->>Factory: HighlightEntity ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
    Factory-->>Manager: highlight entities
    Manager->>DB: saveAll
    Controller-->>OpenCV: ์ €์žฅ ์„ฑ๊ณต ์‘๋‹ต
Loading

5-4-6. ํ•˜์ด๋ผ์ดํŠธ ์ €์žฅ ์‹œ ํ•จ๊ป˜ ๋ณด์กดํ•˜๋Š” ๋ฐ์ดํ„ฐ

ํ•˜์ด๋ผ์ดํŠธ๋Š” ๋‹จ์ˆœ URL ์ €์žฅ์ด ์•„๋‹™๋‹ˆ๋‹ค.

  • highlightId
  • highlightURL
  • highlightKey
  • member
  • backNumber
  • twoPointCount
  • threePointCount
  • videoCreatedAt
  • jobId

์ด ์ •๋ณด๊ฐ€ ์žˆ์–ด์•ผ ๋‚˜์ค‘์—

  • ๋งˆ์ดํŽ˜์ด์ง€ ํ†ต๊ณ„
  • ๊ฒŒ์‹œ๊ธ€ ์—ฐ๊ฒฐ
  • ์บ˜๋ฆฐ๋” ์กฐํšŒ
  • ๋žญํ‚น ๊ณ„์‚ฐ

๊นŒ์ง€ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŽž๏ธ 5-5. ํ•˜์ด๋ผ์ดํŠธ ์กฐํšŒ ๊ธฐ๋Šฅ

๊ด€๋ จ API

Method Endpoint ์ธ์ฆ ์„ค๋ช…
GET /api/highlight/list?page=&size= ์‚ฌ์šฉ์ž JWT ๋‚ด ํ•˜์ด๋ผ์ดํŠธ ํŽ˜์ด์ง• ์กฐํšŒ
GET `/api/highlight?period=WEEKLY MONTHLY` ์‚ฌ์šฉ์ž JWT
GET /api/highlight/calendar?year=&month= ์‚ฌ์šฉ์ž JWT ์›”๋ณ„ ์บ˜๋ฆฐ๋” ์กฐํšŒ
GET /api/highlight/latest?jobId= ์‚ฌ์šฉ์ž JWT ํŠน์ • job์˜ ์ตœ์‹  ๊ฒฐ๊ณผ ์กฐํšŒ

5-5-1. ์กฐํšŒ ๊ธฐ๋Šฅ๋ณ„ ํ๋ฆ„

flowchart TD
    A["HighlightQueryController"] --> B["HighlightManager"]

    B --> C["listByPaging"]
    B --> D["fetchAllMembersHighlights"]
    B --> E["fetchCalendar"]
    B --> F["fetchLatestCreatedHighlights"]

    C --> C1["Pageable ์ƒ์„ฑ"]
    C1 --> C2["member์˜ highlight page ์กฐํšŒ"]
    C2 --> C3["HighlightInfoResponse ๋ณ€ํ™˜"]

    D --> D1["WEEKLY / MONTHLY ๊ธฐ๊ฐ„ ๊ณ„์‚ฐ"]
    D1 --> D2["highlight-post-member-like join query"]
    D2 --> D3["๊ธฐ๊ฐ„ ๋‚ด ์ธ๊ธฐ highlight ๋ฐ˜ํ™˜"]

    E --> E1["year/month ๊ฒ€์ฆ"]
    E1 --> E2["ํ•ด๋‹น ์›” flat data ์กฐํšŒ"]
    E2 --> E3["LocalDate ๊ธฐ์ค€ ๊ทธ๋ฃนํ•‘"]
    E3 --> E4["์บ˜๋ฆฐ๋” ์‘๋‹ต ์ƒ์„ฑ"]

    F --> F1["jobId + memberId ์กฐ๊ฑด ์กฐํšŒ"]
    F1 --> F2["์ตœ์‹  ์ƒ์„ฑ highlight ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜"]
Loading

5-5-2. /api/highlight/list

์ด API๋Š” ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž์˜ ํ•˜์ด๋ผ์ดํŠธ๋ฅผ ํŽ˜์ด์ง•์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • PageRequest.of(page, size) ์ƒ์„ฑ
  • ํšŒ์› ๊ธฐ์ค€ highlight page ์กฐํšŒ
  • HighlightInfoResponse๋กœ ๋งคํ•‘

์ฆ‰, "๋‚ด ํ•˜์ด๋ผ์ดํŠธ ๋ชฉ๋ก" ๊ธฐ๋Šฅ์˜ ๊ธฐ๋ณธ API์ž…๋‹ˆ๋‹ค.

5-5-3. /api/highlight?period=...

์ด API๋Š” ๋‹จ์ˆœํžˆ highlight๋งŒ ๋ณด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, highlight + post + member + like๋ฅผ joinํ•ด์„œ "๊ธฐ๊ฐ„ ๋™์•ˆ ์ธ๊ธฐ ์žˆ์—ˆ๋˜ ํ•˜์ด๋ผ์ดํŠธ"๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ •ํ™•ํžˆ๋Š” ๋‹ค์Œ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

  • ์ง‘๊ณ„ ๊ธฐ๊ฐ„: ์ด๋ฒˆ ์ฃผ ๋˜๋Š” ์ด๋ฒˆ ๋‹ฌ
  • ์กฐ๊ฑด: ํ•ด๋‹น ๊ธฐ๊ฐ„ ๋™์•ˆ ๋ˆŒ๋ฆฐ ์ข‹์•„์š”
  • ๊ฒฐ๊ณผ: ์ข‹์•„์š” ์ˆ˜ ๊ธฐ์ค€ ์ƒ์œ„ ํ•˜์ด๋ผ์ดํŠธ

์ฆ‰, "๋งŽ์ด ๋ณธ ์˜์ƒ"์ด ์•„๋‹ˆ๋ผ "์ข‹์•„์š” ํ™œ๋™์ด ๋งŽ์ด ๋ถ™์€ ํ•˜์ด๋ผ์ดํŠธ"๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

5-5-4. /api/highlight/calendar

์ด API๋Š” ์›”๊ฐ„ ์บ˜๋ฆฐ๋” UI๋ฅผ ์œ„ํ•œ API์ž…๋‹ˆ๋‹ค.

๋™์ž‘ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์—ฐ๋„์™€ ์›”์ด ์œ ํšจํ•œ์ง€ ๊ฒ€์ฆ
  2. ํ•ด๋‹น ์›”์˜ ์‹œ์ž‘ / ์ข…๋ฃŒ ์‹œ๊ฐ ๊ณ„์‚ฐ
  3. ๊ทธ ๊ธฐ๊ฐ„์˜ highlight๋ฅผ flat list๋กœ ์กฐํšŒ
  4. LocalDate ๋‹จ์œ„๋กœ ๊ทธ๋ฃนํ•‘
  5. ๋‚ ์งœ๋ณ„ ๊ฐœ์ˆ˜์™€ ์ƒ์„ธ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฌถ์–ด ์‘๋‹ต

์ฆ‰, DB์—์„œ ๋ฐ”๋กœ ๋‹ฌ๋ ฅ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ณ , flat query ํ›„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์—์„œ ๋‚ ์งœ ๋‹จ์œ„๋กœ ๋ฌถ์–ด ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.

5-5-5. /api/highlight/latest

์ด API๋Š” jobId ๋‹จ์œ„ ๊ฒฐ๊ณผ ํ™•์ธ์šฉ์ž…๋‹ˆ๋‹ค.

  • OpenCV๊ฐ€ ์ž‘์—…์„ ๋๋‚ธ ์งํ›„
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐฉ๊ธˆ ์ƒ์„ฑ๋œ ๊ฒฐ๊ณผ๋งŒ ๋”ฐ๋กœ ๋ณด๊ณ  ์‹ถ์„ ๋•Œ

์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์ „์ฒด highlight ๋ชฉ๋ก์„ ๋‹ค์‹œ ๋’ค์ง€๋Š” ๋Œ€์‹  "์ด๋ฒˆ ์ž‘์—… ๊ฒฐ๊ณผ"๋งŒ ๋น ๋ฅด๊ฒŒ ๊บผ๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ 5-6. ์ปค๋ฎค๋‹ˆํ‹ฐ: ๊ฒŒ์‹œ๊ธ€ / ๋Œ“๊ธ€

๊ฒŒ์‹œ๊ธ€ ๊ด€๋ จ API

Method Endpoint ์ธ์ฆ ์„ค๋ช…
POST /api/post ์‚ฌ์šฉ์ž JWT ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑ
PUT /api/post/{postId} ์‚ฌ์šฉ์ž JWT ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •
DELETE /api/post/{postId} ์‚ฌ์šฉ์ž JWT ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ
GET /api/post/{postId} ์‚ฌ์šฉ์ž JWT ๊ฒŒ์‹œ๊ธ€ ๋‹จ๊ฑด ์กฐํšŒ
GET /api/post ์‚ฌ์šฉ์ž JWT ์ตœ์‹ ์ˆœ/์ธ๊ธฐ์ˆœ ๋ชฉ๋ก ์กฐํšŒ
GET /api/post/mypage ์‚ฌ์šฉ์ž JWT ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ๊ฒŒ์‹œ๊ธ€
GET /api/post/my/like ์‚ฌ์šฉ์ž JWT ๋‚ด๊ฐ€ ์ข‹์•„์š”ํ•œ ๊ฒŒ์‹œ๊ธ€

๋Œ“๊ธ€ ๊ด€๋ จ API

Method Endpoint ์ธ์ฆ ์„ค๋ช…
POST /api/comment ์‚ฌ์šฉ์ž JWT ๋Œ“๊ธ€ ์ž‘์„ฑ
PATCH /api/comment/{commentId} ์‚ฌ์šฉ์ž JWT ๋Œ“๊ธ€ ์ˆ˜์ •
DELETE /api/comment/{commentId} ์‚ฌ์šฉ์ž JWT ๋Œ“๊ธ€ ์‚ญ์ œ
GET /api/comment/{postId} ์‚ฌ์šฉ์ž JWT ๊ฒŒ์‹œ๊ธ€๋ณ„ ๋Œ“๊ธ€ ์กฐํšŒ

5-6-1. ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑ ํ๋ฆ„

sequenceDiagram
    participant Client
    participant Controller as PostCommandController
    participant Service as PostCommandService
    participant Manager as PostManager
    participant HighlightHelper
    participant PostHelper
    participant DB as PostgreSQL
    participant ES as Elasticsearch

    Client->>Controller: POST /api/post
    Controller->>Service: create(request, member)
    Service->>Manager: save(member, request)
    Manager->>HighlightHelper: highlight ์กฐํšŒ
    Manager->>PostHelper: ํšŒ์› ์†Œ์œ  highlight ๊ฒ€์ฆ
    Manager->>PostHelper: hashtag ๊ฒ€์ฆ
    Manager->>DB: post ์ €์žฅ
    Manager->>ES: profile ํ™œ์„ฑ ์‹œ document ์ €์žฅ
    Controller-->>Client: postId ๋ฐ˜ํ™˜
Loading

5-6-2. ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑ ์‹œ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ

PostManager.save๋Š” ์•„๋ž˜ ์ˆœ์„œ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

  1. ์š”์ฒญ highlight ์กฐํšŒ
  2. ์ด highlight๊ฐ€ ํ˜„์žฌ ์‚ฌ์šฉ์ž ์†Œ์œ ์ธ์ง€ ๊ฒ€์ฆ
  3. ํ•ด์‹œํƒœ๊ทธ๊ฐ€ ์œ ํšจํ•œ์ง€ ๊ฒ€์ฆ
  4. PostEntity ์ €์žฅ
  5. Elasticsearch๊ฐ€ ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ document ์ €์žฅ

์ฆ‰, ๊ฒŒ์‹œ๊ธ€์€ ๋…๋ฆฝ ์ฝ˜ํ…์ธ ๊ฐ€ ์•„๋‹ˆ๋ผ "๋‚ด ํ•˜์ด๋ผ์ดํŠธ๋ฅผ ์ฒจ๋ถ€ํ•œ ์ฝ˜ํ…์ธ "๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

5-6-3. ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •๊ณผ ์‚ญ์ œ

  • ์ˆ˜์ •
    • ๊ฒŒ์‹œ๊ธ€ ์กด์žฌ ํ™•์ธ
    • ๊ฒŒ์‹œ๊ธ€ ์†Œ์œ ์ž ๊ฒ€์ฆ
    • ์ƒˆ highlight ๊ฒ€์ฆ
    • hashtag ๊ฒ€์ฆ
    • update
  • ์‚ญ์ œ
    • ๊ฒŒ์‹œ๊ธ€ ์กด์žฌ ํ™•์ธ
    • ๊ฒŒ์‹œ๊ธ€ ์†Œ์œ ์ž ๊ฒ€์ฆ
    • soft delete

๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ๋Š” ๋ฌผ๋ฆฌ ์‚ญ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ๋…ผ๋ฆฌ ์‚ญ์ œ์ž…๋‹ˆ๋‹ค.

5-6-4. ๊ฒŒ์‹œ๊ธ€ ์กฐํšŒ

/api/post

  • type=latest๋ฉด ์ตœ์‹ ์ˆœ ์กฐํšŒ
  • type=popular๋ฉด ์ธ๊ธฐ์ˆœ ์กฐํšŒ
  • slice / no-offset ๋ฐฉ์‹์œผ๋กœ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋Š” ๊ตฌ์กฐ

/api/post/mypage

  • ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ post id ๋ชฉ๋ก์„ ๋จผ์ € ์กฐํšŒ
  • ํ•„์š”ํ•œ post๋ฅผ ๋‹ค์‹œ fetch join์œผ๋กœ ์กฐํšŒ
  • DTO ๋ณ€ํ™˜ ํ›„ ๋ฐ˜ํ™˜

/api/post/my/like

  • ๋‚ด๊ฐ€ ์ข‹์•„์š” ๋ˆ„๋ฅธ ๊ฒŒ์‹œ๊ธ€์„ like ์ƒ์„ฑ ์‹œ๊ฐ„ ์ˆœ์œผ๋กœ ์กฐํšŒ

5-6-5. ๋Œ“๊ธ€ ์ฒ˜๋ฆฌ

๋Œ“๊ธ€์€ ๊ฒŒ์‹œ๊ธ€๋ณด๋‹ค ๋‹จ์ˆœํ•˜์ง€๋งŒ, ์•„๋ž˜ ๊ทœ์น™์ด ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.

  • ์ž‘์„ฑ ์‹œ: ๊ฒŒ์‹œ๊ธ€ ์กด์žฌ ํ™•์ธ ํ›„ ์ €์žฅ
  • ์ˆ˜์ • ์‹œ: ๋Œ“๊ธ€ ์ž‘์„ฑ์ž๋งŒ ์ˆ˜์ • ๊ฐ€๋Šฅ
  • ์‚ญ์ œ ์‹œ: ๋Œ“๊ธ€ ์ž‘์„ฑ์ž๋งŒ ์‚ญ์ œ ๊ฐ€๋Šฅ
  • ์‚ญ์ œ๋Š” soft delete ๋ฐฉ์‹
flowchart LR
    A["๋Œ“๊ธ€ ์š”์ฒญ"] --> B["CommentManager"]
    B --> C["๊ฒŒ์‹œ๊ธ€ ์กด์žฌ ํ™•์ธ"]
    B --> D["๋Œ“๊ธ€ ์ž‘์„ฑ์ž ๊ฒ€์ฆ"]
    B --> E["๋‚ด์šฉ ๊ณต๋ฐฑ ๊ฒ€์ฆ"]
    B --> F["save / update / soft delete"]
Loading

๐Ÿ”Ž 5-7. ๊ฒ€์ƒ‰๊ณผ ์ž๋™์™„์„ฑ

๊ด€๋ จ API

Method Endpoint ์ธ์ฆ ์„ค๋ช…
GET /api/post/list?search= ์‚ฌ์šฉ์ž JWT DB ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰
GET /api/post/list-elastic?search= ์‚ฌ์šฉ์ž JWT Elasticsearch ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰
GET /api/post/suggest?keyword= ์‚ฌ์šฉ์ž JWT ์ž๋™์™„์„ฑ

5-7-1. ๊ฒ€์ƒ‰ ์„ค๊ณ„ ํฌ์ธํŠธ

์ด ํ”„๋กœ์ ํŠธ๋Š” ๊ฒ€์ƒ‰์„ 2๋‹จ๊ณ„๋กœ ๋‚˜๋ˆด์Šต๋‹ˆ๋‹ค.

  • ๊ธฐ๋ณธ ๊ฒ€์ƒ‰: DB LIKE ๊ฒ€์ƒ‰
  • ๊ณ ๊ธ‰ ๊ฒ€์ƒ‰: Elasticsearch ๊ฒ€์ƒ‰

๊ทธ๋ฆฌ๊ณ  Elasticsearch๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋œ ํ™˜๊ฒฝ๋„ ๊ณ ๋ คํ•ด์„œ fallback์„ ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค.

5-7-2. ๊ฒ€์ƒ‰ ๋ถ„๊ธฐ ํ๋ฆ„

flowchart TD
    A["/api/post/list-elastic ์š”์ฒญ"] --> B{"search ๋น„์—ˆ๋Š”๊ฐ€?"}
    B -- ์˜ˆ --> C["์ตœ์‹  ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ๋ฐ˜ํ™˜"]
    B -- ์•„๋‹ˆ์˜ค --> D{"ES helper ํ™œ์„ฑํ™”?"}
    D -- ์•„๋‹ˆ์˜ค --> E["DB LIKE ๊ฒ€์ƒ‰ fallback"]
    D -- ์˜ˆ --> F{"ํ•ด์‹œํƒœ๊ทธ ๊ฒ€์ƒ‰์ธ๊ฐ€?"}
    F -- ์˜ˆ --> G["# ์ œ๊ฑฐ ํ›„ hashTag ๊ฒ€์ƒ‰"]
    F -- ์•„๋‹ˆ์˜ค --> H["title/content ๊ฒ€์ƒ‰"]
    G --> I["search_after ์ •๋ ฌ"]
    H --> I
    I --> J["PostListResponse ๋ฐ˜ํ™˜"]
Loading

5-7-3. ์ผ๋ฐ˜ ๊ฒ€์ƒ‰

DB ๊ธฐ๋ฐ˜ /api/post/list

  • title LIKE %search%
  • content LIKE %search%
  • post_id < lastPostId
  • ORDER BY post_id DESC

์ฆ‰, ์ตœ์‹ ์ˆœ์œผ๋กœ ์ž˜๋ผ ๊ฐ€์ ธ์˜ค๋Š” ์ „ํ˜•์ ์ธ no-offset ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

5-7-4. Elasticsearch ๊ฒ€์ƒ‰

Elasticsearch ๊ฒ€์ƒ‰์€ ์•„๋ž˜ ์ „๋žต์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • title ๊ฐ€์ค‘์น˜: 40
  • content ๊ฐ€์ค‘์น˜: 10
  • ์ •๋ ฌ ์šฐ์„ ์ˆœ์œ„
    • _score DESC
    • likeCnt DESC
    • postId DESC
  • ํŽ˜์ด์ง€๋„ค์ด์…˜
    • search_after

์ฆ‰, ๋‹จ์ˆœ full-text ๊ฒ€์ƒ‰์ด ์•„๋‹ˆ๋ผ "์ œ๋ชฉ์„ ๋” ์ค‘์š”ํ•˜๊ฒŒ ๋ณด๊ณ , ๋™์ ์ด๋ฉด ์ข‹์•„์š” ์ˆ˜์™€ ์ตœ์‹ ์„ฑ์œผ๋กœ ์ •๋ ฌ"ํ•˜๋Š” ์ „๋žต์ž…๋‹ˆ๋‹ค.

5-7-5. ํ•ด์‹œํƒœ๊ทธ ๊ฒ€์ƒ‰

๊ฒ€์ƒ‰์–ด๊ฐ€ #๋กœ ์‹œ์ž‘ํ•˜๋ฉด ์ผ๋ฐ˜ ๊ฒ€์ƒ‰์–ด๊ฐ€ ์•„๋‹ˆ๋ผ ํ•ด์‹œํƒœ๊ทธ๋กœ ํ•ด์„ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

  • #2์ ์Š›
  • #๋ธ”๋ฝ

๋™์ž‘ ๋ฐฉ์‹:

  1. ๋งจ ์•ž # ์ œ๊ฑฐ
  2. ๊ณต๋ฐฑ ์ œ๊ฑฐ
  3. hashTag ํ•„๋“œ ๊ธฐ์ค€ ๊ฒ€์ƒ‰

5-7-6. ์ž๋™์™„์„ฑ

์ž๋™์™„์„ฑ๋„ ์ผ๋ฐ˜ ๊ฒ€์ƒ‰๊ณผ ํ•ด์‹œํƒœ๊ทธ ๊ฒ€์ƒ‰์„ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • ์ผ๋ฐ˜ ๊ฒ€์ƒ‰์–ด
    • title.keyword prefix ๊ธฐ๋ฐ˜ ์ž๋™์™„์„ฑ
  • ํ•ด์‹œํƒœ๊ทธ ๊ฒ€์ƒ‰์–ด
    • hashTag prefix ๊ธฐ๋ฐ˜ ์ž๋™์™„์„ฑ
    • ์ค‘๋ณต ์ œ๊ฑฐ ํ›„ ์ตœ๋Œ€ 5๊ฐœ

์ฆ‰, ๊ฒŒ์‹œ๊ธ€ ์ œ๋ชฉ ์ž๋™์™„์„ฑ๊ณผ ํ•ด์‹œํƒœ๊ทธ ์ž๋™์™„์„ฑ์„ ๊ฐ™์€ API ์•ˆ์—์„œ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

โค๏ธ 5-8. ์ข‹์•„์š”์™€ ๋™์‹œ์„ฑ ์ œ์–ด

๊ด€๋ จ API

Method Endpoint ์ธ์ฆ ์„ค๋ช…
POST /api/like/{postId} ์‚ฌ์šฉ์ž JWT ์ข‹์•„์š” ๋“ฑ๋ก
DELETE /api/like/{postId} ์‚ฌ์šฉ์ž JWT ์ข‹์•„์š” ์ทจ์†Œ

5-8-1. ์™œ ๋™์‹œ์„ฑ ์ œ์–ด๊ฐ€ ์ค‘์š”ํ•œ๊ฐ€

์ข‹์•„์š”๋Š” ์•„๋ž˜ 2๊ฐœ๋ฅผ ๋™์‹œ์— ๋งž์ถฐ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • like_table row ์ •ํ•ฉ์„ฑ
  • post.like_cnt ์ง‘๊ณ„ ์ •ํ•ฉ์„ฑ

์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ๊ฒŒ์‹œ๊ธ€์„ ๋™์‹œ์— ๋ˆ„๋ฅด๋ฉด race condition์ด ์‰ฝ๊ฒŒ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

5-8-2. ์ตœ์ข… ์„ ํƒํ•œ ๋ฐฉ์‹

์ตœ์ข… ๊ตฌํ˜„์€ ๊ฒŒ์‹œ๊ธ€ row๋ฅผ ๋น„๊ด€์  ๋ฝ์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

flowchart TD
    A["์ข‹์•„์š” ์š”์ฒญ"] --> B["Post ์กฐํšŒ with PESSIMISTIC_WRITE"]
    B --> C["์ด๋ฏธ ์ข‹์•„์š” ๋ˆŒ๋ €๋Š”์ง€ ๊ฒ€์ฆ"]
    C --> D["post.likeCnt ์ฆ๊ฐ€"]
    D --> E["LikeEntity ์ €์žฅ"]
    E --> F["ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ"]
Loading

์ทจ์†Œ๋Š” ์—ญ์ˆœ์ž…๋‹ˆ๋‹ค.

flowchart TD
    A["์ข‹์•„์š” ์ทจ์†Œ ์š”์ฒญ"] --> B["Post ์กฐํšŒ with PESSIMISTIC_WRITE"]
    B --> C["memberId + postId๋กœ Like ์กฐํšŒ"]
    C --> D["post.likeCnt ๊ฐ์†Œ"]
    D --> E["LikeEntity ์‚ญ์ œ"]
    E --> F["ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ"]
Loading

5-8-3. ๋‚ด๋ถ€ ๋™์ž‘ ์„ค๋ช…

LikeManager.increase

  1. ๊ฒŒ์‹œ๊ธ€์„ ๋น„๊ด€์  ๋ฝ์œผ๋กœ ์กฐํšŒ
  2. ๊ฐ™์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ ์ข‹์•„์š” ๋ˆŒ๋ €๋Š”์ง€ ํ™•์ธ
  3. post.increase()
  4. Like row ์ €์žฅ

LikeManager.decrease

  1. ๊ฒŒ์‹œ๊ธ€์„ ๋น„๊ด€์  ๋ฝ์œผ๋กœ ์กฐํšŒ
  2. Like row ์กฐํšŒ
  3. post.deleteLike()
  4. Like row ์‚ญ์ œ

5-8-4. ํ…Œ์ŠคํŠธ ๊ด€์ ์—์„œ ์˜๋ฏธ ์žˆ๋Š” ๋ถ€๋ถ„

LikeManagerConcurrencyTest์—๋Š” ๋‹ค์Œ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋™์‹œ์— 100๊ฑด ์ข‹์•„์š” ์ฆ๊ฐ€
  • ๋™์‹œ์— 1,000๊ฑด ์ข‹์•„์š” ์ฆ๊ฐ€
  • ๋™์‹œ์— 10,000๊ฑด ์ข‹์•„์š” ์ฆ๊ฐ€
  • ๋™์‹œ์— 100๊ฑด ์ข‹์•„์š” ๊ฐ์†Œ
  • ๋™์‹œ์— 1,000๊ฑด ์ข‹์•„์š” ๊ฐ์†Œ
  • ๋™์‹œ์— 10,000๊ฑด ์ข‹์•„์š” ๊ฐ์†Œ

๊ทธ๋ฆฌ๊ณ  ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—๋Š” ์‹คํ—˜ ํ”์ ๋„ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ฆ๋ถ„ ์ฟผ๋ฆฌ ๋ฐฉ์‹ ์‹คํ—˜
  • Atomic ๋ฐฉ์‹ ์‹คํ—˜
  • Optimistic Lock ์‹คํ—˜
  • Distributed Lock ์‹คํ—˜

์ฆ‰, ์—ฌ๋Ÿฌ ๋Œ€์•ˆ์„ ๋น„๊ตํ•ด ๋ณธ ๋’ค ํ˜„์žฌ ๊ตฌ์กฐ์—์„œ๋Š” ๋น„๊ด€์  ๋ฝ์ด ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ณ  ๋ช…ํ™•ํ•œ ์„ ํƒ์ด์—ˆ๋‹ค๋Š” ์ ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

๐Ÿ† 5-9. ๋žญํ‚น

๊ด€๋ จ API

Method Endpoint ์„ค๋ช…
GET /api/rank/last-week?date= ์ง€๋‚œ ์ฃผ ๋žญํ‚น ์กฐํšŒ
GET /api/rank/last-month?date= ์ง€๋‚œ ๋‹ฌ ๋žญํ‚น ์กฐํšŒ
GET /api/rank/this-week ์ด๋ฒˆ ์ฃผ ๋žญํ‚น ์กฐํšŒ
GET /api/rank/this-month ์ด๋ฒˆ ๋‹ฌ ๋žญํ‚น ์กฐํšŒ

5-9-1. ๋žญํ‚น์„ ๋‘ ์ข…๋ฅ˜๋กœ ๋‚˜๋ˆˆ ์ด์œ 

๋žญํ‚น์€ ์„ฑ๊ฒฉ์ด ๋‹ค๋ฅธ 2๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • "์ง€๊ธˆ ์ง„ํ–‰ ์ค‘์ธ ๋žญํ‚น"
  • "์ด๋ฏธ ์ข…๋ฃŒ๋œ ๊ธฐ๊ฐ„์˜ ๋žญํ‚น"

์ด ๋‘˜์€ ์กฐํšŒ ์ „๋žต์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

5-9-2. ํ˜„์žฌ ๋žญํ‚น ์กฐํšŒ ํ๋ฆ„

flowchart LR
    A["/api/rank/this-week or this-month"] --> B["RankingController"]
    B --> C["RankingService"]
    C --> D["RankingManager.fetchThisData"]
    D --> E["RankingRedisRepository.getHighlightsWeeklyRanking"]
    E --> F{"Redis ๊ฒฐ๊ณผ ์กด์žฌ?"}
    F -- ์˜ˆ --> G["RankingMapper -> Response"]
    F -- ์•„๋‹ˆ์˜ค --> H["RankingJpaRepository.fetchThisWeekRankingTop10"]
    H --> I["RankingUtil.calculateRanking"]
    I --> G
Loading

5-9-3. ๊ณผ๊ฑฐ ๋žญํ‚น ์กฐํšŒ ํ๋ฆ„

flowchart LR
    A["/api/rank/last-week or last-month"] --> B["RankingController"]
    B --> C["RankingService"]
    C --> D["RankingManager.fetchLastData"]
    D --> E["periodKey ์ƒ์„ฑ"]
    E --> F["MongoDB RankingDocument ์กฐํšŒ"]
    F --> G{"๋ฌธ์„œ ์กด์žฌ?"}
    G -- ์˜ˆ --> H["๋ฌธ์„œ -> Response"]
    G -- ์•„๋‹ˆ์˜ค --> I["ranking.sql JDBC ์ง‘๊ณ„"]
    I --> J["Mapper -> Response"]
Loading

5-9-4. ์ ์ˆ˜ ์‚ฐ์ • ๋ฐฉ์‹

๋žญํ‚น์€ ๋‹จ์ˆœ ์ด์ ๋งŒ ๋ณด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ์ด์  ์šฐ์„ 
  • ๋™์ ์ด๋ฉด 3์ ์Š› ์šฐ์„ 
  • ๋‹ค์‹œ ๋™์ ์ด๋ฉด 2์ ์Š› ์šฐ์„ 

Redis ์ชฝ์—์„œ๋Š” ์ด๋ฅผ ์œ„ํ•ด ๊ฐ€์ค‘์น˜ score๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

score = totalScore * 1_000_000
      + threeScore * 1_000
      + twoScore

์ฆ‰, total > three > two ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์œ ์ง€๋˜๋„๋ก ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

5-9-5. ํ˜„์žฌ ๋žญํ‚น ์ €์žฅ ๊ตฌ์กฐ

ํ˜„์žฌ ์ฃผ๊ฐ„/์›”๊ฐ„ ๋žญํ‚น์€ Redis ZSet์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ๋™์ผ ํšŒ์›์ด ๋‹ค์‹œ ๋ฐ˜์˜๋˜๋ฉด ๊ธฐ์กด ๊ฐ’์„ ์ œ๊ฑฐ ํ›„ ์žฌ์‚ฝ์ž…
  • ์กฐํšŒ๋Š” reverseRangeWithScores๋กœ top 10
  • ์ฃผ๊ฐ„ / ์›”๊ฐ„ ํ‚ค๋Š” ์„œ๋กœ ๋ถ„๋ฆฌ

5-9-6. ๊ณผ๊ฑฐ ๋žญํ‚น ์ €์žฅ ๊ตฌ์กฐ

๊ณผ๊ฑฐ ๋žญํ‚น์€ MongoDB ranking ์ปฌ๋ ‰์…˜ ๋ฌธ์„œ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

  • type
  • periodBegin
  • typePeriodKey
  • top10

์ฆ‰, ๊ณผ๊ฑฐ ๋žญํ‚น์€ "๊ฒฐ๊ณผ ์Šค๋ƒ…์ƒท"์œผ๋กœ ๋‹ค๋ฃจ๊ณ , ํ˜„์žฌ ๋žญํ‚น์€ "์‹ค์‹œ๊ฐ„ ๊ฐ€๋ณ€ ์ƒํƒœ"๋กœ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

5-9-7. ์Šค์ผ€์ค„๋Ÿฌ

flowchart TD
    A["์ฃผ๊ฐ„/์›”๊ฐ„ ์Šค์ผ€์ค„"] --> B["RankingRedisScheduler"]
    B --> C["Redis ํ˜„์žฌ ๋žญํ‚น ์ดˆ๊ธฐํ™”"]

    D["์ผ๊ฐ„/์ฃผ๊ฐ„/์›”๊ฐ„ ๋ฐฐ์น˜ ์Šค์ผ€์ค„"] --> E["RankingBatchScheduler"]
    E --> F["Spring Batch JobLauncher"]
    F --> G["๋žญํ‚น ์Šค๋ƒ…์ƒท ์ €์žฅ ๊ตฌ์กฐ"]
Loading

5-9-8. ๋ฐฐ์น˜ ์„œ๋ฒ„ ์ƒํƒœ

apps/batch-server ์•„๋ž˜์—๋Š” ๋‹ค์Œ ์ฝ”๋“œ๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • Reader
  • Processor
  • Writer
  • Listener
  • Validator
  • Scheduler

์ฆ‰, API ์„œ๋ฒ„์—์„œ ๋žญํ‚น ์ง‘๊ณ„๋ฅผ ๋–ผ์–ด๋‚ด ๋ณ„๋„ ๋ฐฐ์น˜ ์„œ๋ฒ„๋กœ ๋ถ„๋ฆฌํ•˜๋ ค๋Š” ๊ตฌ์กฐ๊ฐ€ ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋งŒ ํ˜„์žฌ ์›ŒํฌํŠธ๋ฆฌ ๊ธฐ์ค€์œผ๋กœ๋Š” ์ผ๋ถ€ Batch config ์ฝ”๋“œ๊ฐ€ ์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ์ƒํƒœ๋ผ, "๋ฐฐ์น˜ ๊ตฌ์กฐ์™€ ๊ณจ๊ฒฉ์€ ์กด์žฌํ•˜์ง€๋งŒ ์ •๋น„ ์ค‘"์œผ๋กœ ๋ณด๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ—ƒ๏ธ 6. ๋ฐ์ดํ„ฐ ๋ชจ๋ธ

6-1. ํ•ต์‹ฌ ERD

ShootPointer_ERD (1)

6-2. ์—”ํ‹ฐํ‹ฐ๋ณ„ ์˜๋ฏธ

์—”ํ‹ฐํ‹ฐ ์˜๋ฏธ
Member ์„œ๋น„์Šค ์‚ฌ์šฉ์ž. ์ด๋ฆ„/์ด๋ฉ”์ผ์€ ์•”ํ˜ธํ™” ์ €์žฅ, ์ง‘๊ณ„ ๋™์˜ ์—ฌ๋ถ€ ํฌํ•จ
BackNumberEntity ๋“ฑ๋ฒˆํ˜ธ ๋งˆ์Šคํ„ฐ
MemberBackNumberEntity ํšŒ์›๊ณผ ๋“ฑ๋ฒˆํ˜ธ์˜ ๋งคํ•‘
HighlightEntity OpenCV๊ฐ€ ์ƒ์„ฑํ•œ ๊ฐœ์ธ ํ•˜์ด๋ผ์ดํŠธ ๋‹จ์œ„
PostEntity ํ•˜์ด๋ผ์ดํŠธ๋ฅผ ์ฒจ๋ถ€ํ•œ ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฒŒ์‹œ๊ธ€
Comment ๊ฒŒ์‹œ๊ธ€ ๋Œ“๊ธ€
LikeEntity ๊ฒŒ์‹œ๊ธ€ ์ข‹์•„์š”
RankingDocument MongoDB์— ์ €์žฅ๋˜๋Š” ๊ธฐ๊ฐ„๋ณ„ ๋žญํ‚น ์Šค๋ƒ…์ƒท

6-3. ๋ฐ์ดํ„ฐ ์„ค๊ณ„ ํฌ์ธํŠธ

  • ๊ฒŒ์‹œ๊ธ€๊ณผ ๋Œ“๊ธ€์€ soft delete
  • ํ•˜์ด๋ผ์ดํŠธ๋Š” ๊ฒŒ์‹œ๊ธ€๊ณผ 1:N ์œ ์‚ฌ ๊ด€๊ณ„๋กœ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • Member๋Š” BackNumber์™€ ์ง์ ‘ ๊ฒฐํ•ฉํ•˜์ง€ ์•Š๊ณ  ๋ธŒ๋ฆฟ์ง€ ํ…Œ์ด๋ธ” ์‚ฌ์šฉ
  • Ranking์€ ์šด์˜ ํ…Œ์ด๋ธ”์— ๋งค๋ฒˆ ์ง‘๊ณ„ํ•˜์ง€ ์•Š๊ณ  ๋ฌธ์„œ ์Šค๋ƒ…์ƒท ๋ณด์กด

โš™๏ธ 7. ์šด์˜ / ๋ฐฐํฌ / CI

7-1. Docker Compose ๊ตฌ์„ฑ

ํ˜„์žฌ docker-compose.yml์€ ์•„๋ž˜ ์„œ๋น„์Šค๋ฅผ ํ•จ๊ป˜ ์˜ฌ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • PostgreSQL
  • MongoDB
  • Elasticsearch
  • Kibana
  • API Server
  • Batch Server

7-2. ์šด์˜ ์ปจํ…Œ์ด๋„ˆ ๊ตฌ์„ฑ

flowchart LR
    A["docker-compose"] --> B["postgres"]
    A --> C["mongo"]
    A --> D["elasticsearch"]
    A --> E["kibana"]
    A --> F["api-server"]
    A --> G["batch-server"]

    F --> B
    F --> C
    F --> D
    F --> G
Loading

7-3. Jenkins ๋ฐฐํฌ ํŒŒ์ดํ”„๋ผ์ธ

flowchart TD
    A["Jenkins Job ์‹œ์ž‘"] --> B["Git clone"]
    B --> C["๋น„๊ณต๊ฐœ application / env ํŒŒ์ผ ์ฃผ์ž…"]
    C --> D["๊ธฐ์กด ์ปจํ…Œ์ด๋„ˆ ๋ฐ ํฌํŠธ ์ •๋ฆฌ"]
    D --> E["Elasticsearch ๋ณผ๋ฅจ ๊ถŒํ•œ ์ˆ˜์ •"]
    E --> F["docker-compose up -d --build"]
    F --> G["API / DB / ES / Mongo ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋™"]
Loading

7-4. Jenkinsfile์—์„œ ์‹ค์ œ๋กœ ํ•˜๋Š” ์ผ

  1. main ๋ธŒ๋žœ์น˜ clone
  2. credential๋กœ ๋น„๊ณต๊ฐœ ์„ค์ • ํŒŒ์ผ ๋ณต์‚ฌ
  3. ๊ธฐ์กด ํฌํŠธ/์ปจํ…Œ์ด๋„ˆ cleanup
  4. Elasticsearch data/log ๊ถŒํ•œ ์ˆ˜์ •
  5. docker-compose up -d --build

์ฆ‰, ๋‹จ์ˆœ jar ๋ฐฐํฌ๊ฐ€ ์•„๋‹ˆ๋ผ "์—ฌ๋Ÿฌ ์ธํ”„๋ผ ์„œ๋น„์Šค์™€ ์•ฑ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ•จ๊ป˜ ๊ธฐ๋™ํ•˜๋Š” ๋ฐฐํฌ"๋ฅผ ์ž๋™ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

โœ… 8. ํ…Œ์ŠคํŠธ์™€ ํ’ˆ์งˆ ๊ด€๋ฆฌ

8-1. ํ…Œ์ŠคํŠธ ๋ฒ”์œ„

๋Œ€ํ‘œ์ ์œผ๋กœ ์•„๋ž˜ ์˜์—ญ์ด ํ…Œ์ŠคํŠธ๋ฉ๋‹ˆ๋‹ค.

์˜์—ญ ์˜ˆ์‹œ
ํšŒ์› MemberManagerTest, MemberCommandControllerTest, KakaoApiHelperImplTest
๋“ฑ๋ฒˆํ˜ธ BackNumberManagerTest, BackNumberControllerTest
ํ•˜์ด๋ผ์ดํŠธ HighlightManagerTest, HighlightQueryControllerTest, HighlightFactoryTest
๊ฒŒ์‹œ๊ธ€ PostManagerTest, PostCommandControllerTest, PostQueryControllerTest
๋Œ“๊ธ€ CommentManagerTest, CommentCommandControllerTest
์ข‹์•„์š” LikeManagerTest, LikeManagerConcurrencyTest
๋žญํ‚น RankingManagerTest, RankingControllerTest, RankingRedisSchedulerTest

8-2. ํ’ˆ์งˆ ๊ด€๋ฆฌ ํฌ์ธํŠธ

  • ์ปจํŠธ๋กค๋Ÿฌ / ๋น„์ฆˆ๋‹ˆ์Šค / ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ํ…Œ์ŠคํŠธ ๋ถ„๋ฆฌ
  • ๋™์‹œ์„ฑ ํ…Œ์ŠคํŠธ ๋ณ„๋„ ์ž‘์„ฑ
  • Elasticsearch ์—ฐ๋™ ํ…Œ์ŠคํŠธ ๋ถ„๋ฆฌ
  • JaCoCo ๋ฆฌํฌํŠธ ์ƒ์„ฑ ์„ค์ • ๊ด€๋ฆฌ

๐Ÿงฑ 9. ๋ฉ€ํ‹ฐ๋ชจ๋“ˆ ๋ฆฌํŒฉํ„ฐ๋ง

9-1. ํ˜„์žฌ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์ƒํƒœ

.
โ”œโ”€โ”€ apps
โ”‚   โ”œโ”€โ”€ api-server
โ”‚   โ””โ”€โ”€ batch-server
โ”œโ”€โ”€ libs
โ”‚   โ”œโ”€โ”€ common
โ”‚   โ””โ”€โ”€ support
โ”œโ”€โ”€ modules
โ”‚   โ”œโ”€โ”€ community-context
โ”‚   โ”œโ”€โ”€ global
โ”‚   โ”œโ”€โ”€ media-processing-context
โ”‚   โ””โ”€โ”€ member-context
โ””โ”€โ”€ src/main/java/com/midas/shootpointer
    โ”œโ”€โ”€ domain
    โ”œโ”€โ”€ global
    โ””โ”€โ”€ infrastructure

9-2. ์™œ ๋ฆฌํŒฉํ„ฐ๋ง์„ ์‹œ์ž‘ํ–ˆ๋Š”๊ฐ€

๊ธฐ์กด src/main/java/com/midas/shootpointer ๊ตฌ์กฐ๋Š” ๊ธฐ๋Šฅ์ด ๋Š˜์ˆ˜๋ก ๋‹ค์Œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.

  • ๋„๋ฉ”์ธ ๊ฒฝ๊ณ„๊ฐ€ ํ๋ ค์ง
  • ๊ณตํ†ต ์ฝ”๋“œ๊ฐ€ ์—ฌ๊ธฐ์ €๊ธฐ ํฉ์–ด์ง
  • API ์„œ๋ฒ„์™€ ๋ฐฐ์น˜ ์„œ๋ฒ„์˜ ์ฑ…์ž„์ด ์„ž์ž„
  • ํ…Œ์ŠคํŠธ์™€ ๋ฐฐํฌ ๋‹จ์œ„๊ฐ€ ์ปค์ง

๊ทธ๋ž˜์„œ ๋‹ค์Œ ๋ฐฉํ–ฅ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ง„์ž…์  ๋ถ„๋ฆฌ: api-server, batch-server
  • ์ปจํ…์ŠคํŠธ ๋ถ„๋ฆฌ: member-context, community-context, media-processing-context
  • ๊ณตํ†ต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”์ถœ: libs/common, libs/support

9-3. ๋ฆฌํŒฉํ„ฐ๋ง ๋ชฉํ‘œ ๊ตฌ์กฐ

flowchart LR
    A["Legacy src/main/java"] --> B["apps"]
    A --> C["modules"]
    A --> D["libs"]

    B --> B1["api-server"]
    B --> B2["batch-server"]

    C --> C1["member-context"]
    C --> C2["community-context"]
    C --> C3["media-processing-context"]
    C --> C4["global"]

    D --> D1["common"]
    D --> D2["support"]
Loading

About

๐Ÿ€ ๊ฐœ์ธ ๋งž์ถคํ˜• ๋†๊ตฌ ํ•˜์ด๋ผ์ดํŠธ ์ถ”์ถœ ๐Ÿ€

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors