[๐Ÿ”ฅTroubleShooting - TicToc๐Ÿ”ฅ] ์žฅ๊ธฐ ํ”„๋กœ์ ํŠธ ์ด๋Œ€๋กœ.. ๊ดœ์ฐฎ์„๊นŒ..โ“๐Ÿ’ฆ๐Ÿ’ฆ

._mungยท2025๋…„ 3์›” 7์ผ
0

TicToc

๋ชฉ๋ก ๋ณด๊ธฐ
1/6

๐Ÿ“Œ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

ํŒ€์› : ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ
๊ธฐ๊ฐ„ : 2025.01 ~ ์ง„ํ–‰ ์ค‘
๋งํฌ : https://github.com/M-ung/TicToc_Server
์„œ๋น„์Šค ๋‚ด์šฉ : ๋‹น์‹ ์˜ ์‹œ๊ฐ„์— ๊ฐ€์น˜๋ฅผ ๋งค๊ธฐ๋‹ค, ์‹œ๊ฐ„ ๊ฑฐ๋ž˜ ๊ฒฝ๋งค ํ”Œ๋žซํผ


๐Ÿ”ฅTroubleShooting๐Ÿ”ฅ

Problems

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

1. ์œ ์ง€๋ณด์ˆ˜์™€ ํ™•์žฅ์„ฑ์˜ ์–ด๋ ค์›€
2. ๋ฐฐํฌํ•  ๋•Œ ๋นŒ๋“œ ์†๋„ ์ €ํ•˜
3. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ์˜ ๋ถˆํŽธํ•จ


How

์œ„ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ธฐ์กด์˜ ๋‹จ์ผ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ๋ณด๋‹ค ํ—ฅ์‚ฌ๊ณ ๋‚  ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๋ฉ€ํ‹ฐ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋ž˜ ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

1. ํ”„๋กœ์ ํŠธ ๋ฉ€ํ‹ฐ๋ชจ๋“ˆ ์„ธํŒ…
2. ํ—ฅ์‚ฌ๊ณ ๋‚  ์•„ํ‚คํ…์ฒ˜ ์ ์šฉ


Process

1. ํ”„๋กœ์ ํŠธ ๋ฉ€ํ‹ฐ๋ชจ๋“ˆ ์„ธํŒ…
๋จผ์ € ๋‹จ์ผ๋ชจ๋“ˆ์—์„œ ๋ฉ€ํ‹ฐ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ๋กœ ๊ตฌ์„ฑํ•˜๊ณ , ๊ฐ ๋ชจ๋“ˆ ๊ณ„์ธต์„ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌ์„ฑํ–ˆ๋‹ค.

๐Ÿ“ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

tictoc-api ## ๐Ÿ—‚๏ธ API ๊ด€๋ จ ๋ชจ๋“ˆ
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ build.gradle
โ””โ”€โ”€ src
    โ”œโ”€โ”€ main
    โ”‚   โ”œโ”€โ”€ java
    โ”‚   โ”‚   โ””โ”€โ”€ tictoc
    โ”‚   โ”‚       โ”œโ”€โ”€ TicTocApiApplication.java
    โ”‚   โ”‚       โ”œโ”€โ”€ auction 
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ adapter (## ๐Ÿ—‚๏ธ API ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ dto (## ๐Ÿ—‚๏ธ ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ mapper (## ๐Ÿ—‚๏ธ ๊ฐ์ฒด ๋ณ€ํ™˜)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ port (## ๐Ÿ—‚๏ธ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ์ธํ„ฐํŽ˜์ด์Šค)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ application (## ๐Ÿ—‚๏ธ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ๊ตฌํ˜„์ฒด)
    โ”‚   โ”‚       โ”œโ”€โ”€ bid
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ adapter (## ๐Ÿ—‚๏ธ API ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ dto (## ๐Ÿ—‚๏ธ ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ mapper (## ๐Ÿ—‚๏ธ ๊ฐ์ฒด ๋ณ€ํ™˜)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ port (## ๐Ÿ—‚๏ธ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ์ธํ„ฐํŽ˜์ด์Šค)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ application (## ๐Ÿ—‚๏ธ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ๊ตฌํ˜„์ฒด)
    โ”‚   โ”‚       โ”œโ”€โ”€ user
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ adapter (## ๐Ÿ—‚๏ธ API ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ dto (## ๐Ÿ—‚๏ธ ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ mapper (## ๐Ÿ—‚๏ธ ๊ฐ์ฒด ๋ณ€ํ™˜)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ port (## ๐Ÿ—‚๏ธ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ์ธํ„ฐํŽ˜์ด์Šค)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ application (## ๐Ÿ—‚๏ธ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ๊ตฌํ˜„์ฒด)
    โ”‚   โ”‚       โ”œโ”€โ”€ config
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ CorsFilter.java 
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ SpringDocOpenApiConfig.java (## ๐Ÿ“„ Swagger)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ WebConfig.java
    โ”‚   โ”‚       โ”‚   โ””โ”€โ”€ security
    โ”‚   โ”œโ”€โ”€ resources
    โ”‚   โ”‚   โ”œโ”€โ”€ application.yml (## ๐Ÿ“„ ๊ณตํ†ต application.yml)
    โ”‚   โ”‚   โ”œโ”€โ”€ application-dev.yml (## ๐Ÿ“„ ๊ฐœ๋ฐœ application.yml)
    โ”‚   โ”‚   โ”œโ”€โ”€ application-prod.yml (## ๐Ÿ“„ ๋ฐฐํฌ application.yml)

tictoc-batch (## ๐Ÿ—‚๏ธ Spring Batch ๊ด€๋ จ ๋ชจ๋“ˆ)
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ build.gradle
โ””โ”€โ”€ src
    โ”œโ”€โ”€ main
    โ”‚   โ”œโ”€โ”€ java
    โ”‚   โ”‚   โ””โ”€โ”€ tictoc
    โ”‚   โ”‚       โ”œโ”€โ”€ TicTocBatchApplication.java
    โ”‚   โ”‚       โ”œโ”€โ”€ userLoginHistory
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ config (## ๐Ÿ—‚๏ธ Spring Batch)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ event (## ๐Ÿ—‚๏ธ Kafka Consumer)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ scheduler (## ๐Ÿ—‚๏ธ Spring Batch Scheduler)
    โ”‚   โ”œโ”€โ”€ resources
    โ”‚   โ”‚   โ”œโ”€โ”€ application.yml (## ๐Ÿ“„ ๊ณตํ†ต application.yml)
    โ”‚   โ”‚   โ”œโ”€โ”€ application-dev.yml (## ๐Ÿ“„ ๊ฐœ๋ฐœ application.yml)
    โ”‚   โ”‚   โ”œโ”€โ”€ application-prod.yml (## ๐Ÿ“„ ๋ฐฐํฌ application.yml)

tictoc-common (## ๐Ÿ—‚๏ธ ๊ณตํ†ต ๋กœ์ง ๊ด€๋ จ ๋ชจ๋“ˆ)
โ”œโ”€โ”€ build.gradle
โ””โ”€โ”€ src
    โ”œโ”€โ”€ main
    โ”‚   โ”œโ”€โ”€ java
    โ”‚   โ”‚   โ””โ”€โ”€ tictoc
    โ”‚   โ”‚       โ”œโ”€โ”€ TicTocCommonApplication.java
    โ”‚   โ”‚       โ”œโ”€โ”€ annotation (## ๐Ÿ—‚๏ธ ์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜)
    โ”‚   โ”‚       โ”œโ”€โ”€ aspect (## ๐Ÿ—‚๏ธ AOP)
    โ”‚   โ”‚       โ”œโ”€โ”€ config (## ๐Ÿ—‚๏ธ ๊ณตํ†ต ์„ค์ •)
    โ”‚   โ”‚       โ”œโ”€โ”€ constants (## ๐Ÿ—‚๏ธ ๊ณตํ†ต ์ƒ์ˆ˜)
    โ”‚   โ”‚       โ”œโ”€โ”€ error (## ๐Ÿ—‚๏ธ ์ปค์Šคํ…€ ์—๋Ÿฌ)
    โ”‚   โ”‚       โ”œโ”€โ”€ model (## ๐Ÿ—‚๏ธ ๊ณตํ†ต ๊ฐ์ฒด)
    โ”‚   โ”œโ”€โ”€ resources
    โ”‚   โ”‚   โ”œโ”€โ”€ application-common.yml (## ๐Ÿ“„ common application.yml)

tictoc-domain (## ๐Ÿ—‚๏ธ ๋„๋ฉ”์ธ ๊ด€๋ จ ๋ชจ๋“ˆ)
โ”œโ”€โ”€ build.gradle
โ””โ”€โ”€ src
    โ”œโ”€โ”€ main
    โ”‚   โ”œโ”€โ”€ java
    โ”‚   โ”‚   โ””โ”€โ”€ tictoc
    โ”‚   โ”‚       โ”œโ”€โ”€ TicTocDomainApplication.java
    โ”‚   โ”‚       โ”œโ”€โ”€ auction
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ adapter (## ๐Ÿ—‚๏ธ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตฌํ˜„์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ dto (## ๐Ÿ—‚๏ธ ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ event (## ๐Ÿ—‚๏ธ Redis Event)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ exception (## ๐Ÿ—‚๏ธ ์ปค์Šคํ…€ ์˜ˆ๋Ÿฌ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ model (## ๐Ÿ—‚๏ธ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ port (## ๐Ÿ—‚๏ธ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ repository (## ๐Ÿ—‚๏ธ DB์™€ ์ ‘๊ทผํ•˜๋Š” ์ €์žฅ์†Œ)
    โ”‚   โ”‚       โ”œโ”€โ”€ bid
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ adapter (## ๐Ÿ—‚๏ธ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตฌํ˜„์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ dto (## ๐Ÿ—‚๏ธ ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ exception (## ๐Ÿ—‚๏ธ ์ปค์Šคํ…€ ์˜ˆ๋Ÿฌ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ model (## ๐Ÿ—‚๏ธ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ port (## ๐Ÿ—‚๏ธ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ repository (## ๐Ÿ—‚๏ธ DB์™€ ์ ‘๊ทผํ•˜๋Š” ์ €์žฅ์†Œ)
    โ”‚   โ”‚       โ”œโ”€โ”€ config (## ๐Ÿ—‚๏ธ ๋„๋ฉ”์ธ ์„ค์ •)
    โ”‚   โ”‚       โ”œโ”€โ”€ notification
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ model (## ๐Ÿ—‚๏ธ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ)
    โ”‚   โ”‚       โ”œโ”€โ”€ payment
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ model (## ๐Ÿ—‚๏ธ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ)
    โ”‚   โ”‚       โ”œโ”€โ”€ propfile
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ adapter (## ๐Ÿ—‚๏ธ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตฌํ˜„์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ model (## ๐Ÿ—‚๏ธ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ port (## ๐Ÿ—‚๏ธ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ repository (## ๐Ÿ—‚๏ธ DB์™€ ์ ‘๊ทผํ•˜๋Š” ์ €์žฅ์†Œ)
    โ”‚   โ”‚       โ”œโ”€โ”€ user
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ adapter (## ๐Ÿ—‚๏ธ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตฌํ˜„์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ dto (## ๐Ÿ—‚๏ธ ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ exception (## ๐Ÿ—‚๏ธ ์ปค์Šคํ…€ ์˜ˆ๋Ÿฌ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ model (## ๐Ÿ—‚๏ธ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ port (## ๐Ÿ—‚๏ธ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ repository (## ๐Ÿ—‚๏ธ DB์™€ ์ ‘๊ทผํ•˜๋Š” ์ €์žฅ์†Œ)
    โ”‚   โ”œโ”€โ”€ resources
    โ”‚   โ”‚   โ”œโ”€โ”€ application-domain.yml (## ๐Ÿ“„ domain application.yml)

tictoc-external (## ๐Ÿ—‚๏ธ ์™€๋ถ€ ๋กœ์ง ๊ด€๋ จ ๋ชจ๋“ˆ)
โ”œโ”€โ”€ build.gradle
โ””โ”€โ”€ src
    โ”œโ”€โ”€ main
    โ”‚   โ”œโ”€โ”€ java
    โ”‚   โ”‚   โ””โ”€โ”€ tictoc
    โ”‚   โ”‚       โ”œโ”€โ”€ TicTocExternalApplication.java
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ config (## ๐Ÿ—‚๏ธ openFeign ์„ค์ •)
    โ”‚   โ”‚       โ”œโ”€โ”€ kakao (## ๐Ÿ—‚๏ธ Kakao ์—ฐ๊ฒฐ)
    โ”‚   โ”œโ”€โ”€ resources
    โ”‚   โ”‚   โ”œโ”€โ”€ application-external.yml (## ๐Ÿ“„ external application.yml)

tictoc-infrastructure (## ๐Ÿ—‚๏ธ Redis, Kafka ๊ด€๋ จ ๋ชจ๋“ˆ)
โ”œโ”€โ”€ build.gradle
โ””โ”€โ”€ src
    โ”œโ”€โ”€ main
    โ”‚   โ”œโ”€โ”€ java
    โ”‚   โ”‚   โ””โ”€โ”€ tictoc
    โ”‚   โ”‚       โ”œโ”€โ”€ TicTocInfrastructureApplication.java
    โ”‚   โ”‚       โ”œโ”€โ”€ kafka 
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ config (## ๐Ÿ—‚๏ธ Kafka ์„ค์ •)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ event (## ๐Ÿ—‚๏ธ Kafka Producer)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ exception (## ๐Ÿ—‚๏ธ ์ปค์Šคํ…€ ์˜ˆ๋Ÿฌ)
    โ”‚   โ”‚       โ”œโ”€โ”€ redis 
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ auction
    โ”‚   โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ adapter (## ๐Ÿ—‚๏ธ Redis ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ๊ตฌํ˜„์ฒด)
    โ”‚   โ”‚       โ”‚   โ”‚   โ”œโ”€โ”€ port (## ๐Ÿ—‚๏ธ Redis ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ์ธํ„ฐํŽ˜์ด์Šค)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ config (## ๐Ÿ—‚๏ธ Redis ์„ค์ •)
    โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ exception (## ๐Ÿ—‚๏ธ ์ปค์Šคํ…€ ์˜ˆ๋Ÿฌ)
    โ”‚   โ”œโ”€โ”€ resources
    โ”‚   โ”‚   โ”œโ”€โ”€ application-infrastructure.yml (## ๐Ÿ“„ infrastructure application.yml)

๊ทธ๋ฆฌ๊ณ  ๊ฐ ๋ชจ๋“ˆ์ด ์ •์ƒ์ ์œผ๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ settings.gradle์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ๋‹ค.
๐Ÿ“ settings.gradle

rootProject.name = 'TicToc'
include 'tictoc-common'
include 'tictoc-api'
include 'tictoc-domain'
include 'tictoc-infrastructure'
include 'tictoc-batch'
include 'tictoc-external'

๋˜ tictoc-api์™€ tictoc-batch๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋™์ž‘์‹œํ‚ฌ ๋ชจ๋“ˆ์ด๊ณ  tictoc-domain, tictoc-common, tictoc-external, tictoc-infrastructure์€ ์˜์กดํ•  ๋ชจ๋“ˆ์ด๊ธฐ์— ์•„๋ž˜์™€ ๊ฐ™์ด build.gradle์„ ์ž‘์„ฑํ–ˆ๋‹ค.

๐Ÿ“ tictoc-api build.gradle

bootJar {
    archiveBaseName = "app"
    archiveVersion = ""
}

processResources {
    from(project(":tictoc-common").file("src/main/resources")) {
        into("BOOT-INF/classes")
    }
    from(project(":tictoc-domain").file("src/main/resources")) {
        into("BOOT-INF/classes")
    }
    from(project(":tictoc-infrastructure").file("src/main/resources")) {
        into("BOOT-INF/classes")
    }
    from(project(":tictoc-external").file("src/main/resources")) {
        into("BOOT-INF/classes")
    }
}

jar {
    enabled = false
}

dependencies {
    implementation project(':tictoc-common')
    implementation project(':tictoc-domain')
    implementation project(':tictoc-infrastructure')
    implementation project(':tictoc-external')

    // Swagger
    implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
    implementation 'javax.servlet:javax.servlet-api:4.0.1'

    //security
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    testImplementation 'org.springframework.security:spring-security-test'
    implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
    implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
    implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

    // mapstruct
    implementation 'org.mapstruct:mapstruct:1.5.5.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
}

๐Ÿ“ tictoc-batch build.gradle

bootJar {
    archiveBaseName = "app"
    archiveVersion = ""
}

processResources {
    from(project(":tictoc-domain").file("src/main/resources")) {
        into("BOOT-INF/classes")
    }
}

jar {
    enabled = false
}

dependencies {
    // Spring Batch
    implementation 'org.springframework.boot:spring-boot-starter-batch'
    implementation 'org.springframework.batch:spring-batch-core'

    implementation project(':tictoc-domain')
    implementation project(':tictoc-common')
    implementation project(':tictoc-infrastructure')
}

๐Ÿ“ tictoc-domain build.gradle

bootJar.enabled = false

jar.enabled = true

dependencies {
    implementation project(':tictoc-common')
    implementation project(':tictoc-infrastructure')

    // mysql
    runtimeOnly 'com.mysql:mysql-connector-j'
}

def generated = layout.buildDirectory.dir("generated/querydsl")

sourceSets {
    main {
        java {
            srcDirs += generated
        }
    }
}

clean.doLast {
    file(generated).deleteDir()
}

๐Ÿ“ tictoc-common build.gradle

bootJar.enabled = false
jar.enabled = true

dependencies {
}

๐Ÿ“ tictoc-external build.gradle

bootJar.enabled = false
jar.enabled = true

dependencies {
    implementation project(':tictoc-common')
}

๐Ÿ“ tictoc-infrastructure build.gradle

bootJar.enabled = false
jar.enabled = true

dependencies {
    implementation project(':tictoc-common')

    // redis
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
}

๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐ ๋ชจ๋“ˆ์— ์—ญํ• ์— ๋งž๊ฒŒ application.yml ํŒŒ์ผ์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ๋‹ค.

๐Ÿ“ application.yml (tictoc-api)

jwt:
  secret: ${JWT_SECRET}
  accessTokenExpireTime: ${JWT_ACCESS_EXPIRE_TIME}
  refreshTokenExpireTime: ${JWT_REFRESH_EXPIRE_TIME}
server:
  port: 8080
  tomcat:
    threads:
      max: 200
      min-spare: 10
    accept-count: 100
spring:
  jpa:
    database-platform: org.hibernate.dialect.MySQL8Dialect
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
        show_sql: false
  profiles:
    active: dev
    include:
      - domain
      - external
      - infrastructure
  config:
    import: optional:file:.env[.properties]
  threads:
    virtual:
      enabled: true
  servlet:
    multipart:
      max-file-size: 5MB
logging.level:
  org.hibernate.SQL: debug
  org.hibernate.orm.jdbc.bind: trace
  org.springframework.web.cors: DEBUG

๐Ÿ“ application.yml (tictoc-batch)

jwt:
  secret: ${JWT_SECRET}
  accessTokenExpireTime: ${JWT_ACCESS_EXPIRE_TIME}
  refreshTokenExpireTime: ${JWT_REFRESH_EXPIRE_TIME}
server:
  port: 8081
  tomcat:
    threads:
      max: 200
      min-spare: 10
    accept-count: 100
spring:
  profiles:
    active: dev
    include:
      - domain
      - external
      - infrastructure
  config:
    import: optional:file:.env[.properties]
  batch:
    jdbc:
      initialize-schema: always
  threads:
    virtual:
      enabled: true
  servlet:
    multipart:
      max-file-size: 5MB
logging.level:
  org.hibernate.SQL: debug
  org.hibernate.orm.jdbc.bind: trace
  org.springframework.web.cors: DEBUG

๐Ÿ“ application-domain.yml

spring:
  datasource:
    master:
      hikari:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://${DB_HOST}:${MASTER_DB_PORT}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8
        username: ${DB_USER}
        password: ${DB_PASSWORD}
    slave:
      hikari:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://${DB_HOST}:${SLAVE_DB_PORT}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8
        username: ${DB_USER}
        password: ${DB_PASSWORD}

๐Ÿ“ application-external.yml

feign:
  kakao:
    kakao_get_token_name: ${KAKAO_GET_TOKEN_NAME}
    kakao_get_profile_name: ${KAKAO_GET_PROFILE_NAME}
    kakao_get_token_info_name: ${KAKAO_GET_TOKEN_INFO_NAME}
    get-kauth-url: ${KAKAO_KAUTH_URL}
    get-kapi-url: ${KAKAO_KAPI_URL}
    redirect: ${KAKAO_REDIRECT}
    rest-api-key: ${KAKAO_REST_API_KEY}

๐Ÿ“ application-infrastructure.yml

spring:
  cache:
    type: redis
  data:
    redis:
      host: ${REDIS_HOST}
      port: ${REDIS_PORT}
  kafka:
    bootstrap-servers: ${KAFKA_HOST}:${KAFKA_PORT}
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
    listener:
      type: ${KAFKA_TYPE}
    consumer:
      group-id: ${KAFKA_GROUP}
      auto-offset-reset: latest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer

2. ํ—ฅ์‚ฌ๊ณ ๋‚  ์•„ํ‚คํ…์ฒ˜ ์ ์šฉ
์œ„์— ์ ์€ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋ณด๋ฉด ํ—ฅ์‚ฌ๊ณ ๋‚  ์•„ํ‚คํ…์ฒ˜๋ฅผ ํ™œ์šฉํ•œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด, ๋จผ์ € tictoc-api ๋ชจ๋“ˆ์˜ Controller ๊ณ„์ธต์—์„œ ์ด๋ฅผ ์ˆ˜์‹ ํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ์ธํ„ฐํŽ˜์ด์Šค ๊ณ„์ธต์ธ UseCase๋ฅผ ํ†ตํ•ด ์š”์ฒญ์ด ์ „๋‹ฌ๋˜๋ฉฐ, ํ•ด๋‹น ์š”์ฒญ์€ ๊ตฌํ˜„์ฒด์ธ Service ๊ณ„์ธต์—์„œ ์ฒ˜๋ฆฌ๋œ๋‹ค.
๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ณผ์ •์—์„œ ๋„๋ฉ”์ธ ๊ฐ์ฒด ๋ฐ DB ์ ‘๊ทผ์ด ํ•„์š”ํ•  ๊ฒฝ์šฐ, tictoc-domain ๋ชจ๋“ˆ์˜ Port ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ, Port ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด์ธ Adaptor๋Š” Repository๋ฅผ ํ™œ์šฉํ•˜์—ฌ DB์— ์ ‘๊ทผํ•˜์—ฌ ์ˆ˜ํ–‰ํ•˜๋Š” ํ๋ฆ„์ด๋‹ค.

์œ„ ์‚ฌ์ง„์„ ๋ณด๋ฉด DB๊ฐ€ Master์™€ Slave๋กœ ๋‚˜๋ˆ ์ ธ ์žˆ๊ณ , Query์™€ Command๋ผ๋Š” ๋‹จ์–ด๊ฐ€ ๋ณด์ธ๋‹ค. ์ด๋Š” ๋‹ค์Œ ๊ธ€์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃจ๊ฒ ์ง€๋งŒ, ์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•ด ๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.

Query์™€ Command๋ฅผ ๋‚˜๋ˆ„๋Š” ๊ธฐ์ค€์€ ํฌ๊ฒŒ ์—ญํ• ์ด "์“ฐ๊ธฐ"๋ƒ "์ฝ๊ธฐ"๋ƒ์— ๋”ฐ๋ผ ๊ฒฐ์ •ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ์ด์œ ๋Š” CQRSํŒจํ„ด, DB๋ถ„๋ฆฌ, ์†๋„ ๊ฐœ์„ , ๋“ฑ ์—ฌ๋Ÿฌ ์ด์œ ๊ฐ€ ์žˆ๊ฒ ์ง€๋งŒ, ์ €๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ์ตœ๋Œ€ํ•œ ๋ชจ๋“ˆํ™”ํ•˜๊ณ  ์‹ถ๊ณ  ๊ฐ์ฒด๋ฅผ ์—ญํ•  ๋ณ„๋กœ ๊น”๋”ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ์–ด์„œ ์œ„ ๋„ค์ด๋ฐ ๋ฒ•์น™์„ ๊ฐ€์ ธ์˜ค๊ณ  ์žˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” DB๋ฅผ Mysql์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ด๋ฅผ Master์™€ Slave๋กœ ๋‚˜๋ˆ ์„œ ์œ„ ์•„ํ‚คํ…์ฒ˜ ๊ทธ๋ฆผ๋Œ€๋กœ ๊ด€๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.


Result

๋ฌธ์ œ ํ•ด๊ฒฐ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์—ˆ๋‹ค.
1. ์œ ์ง€๋ณด์ˆ˜์„ฑ ๋ฐ ํ™•์žฅ์„ฑ ํ–ฅ์ƒ.
2. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋กœ์ง ๋ถ„๋ฆฌ.

์ตœ์ข… ํ”„๋กœ์ ํŠธ ๋ชจ๋“ˆ ํ˜•ํƒœ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

๋˜ "๊ฒฝ๋งค ๋“ฑ๋ก" ๊ธฐ๋Šฅ์„ ์•„๋ž˜์™€ ๊ฐ™์ด ํ—ฅ์‚ฌ๊ณ ๋‚  ์•„ํ‚คํ…์ฒ˜๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๐Ÿ“ AuctionCommandController.java

๐Ÿ“ AuctionCommandUseCase.java

๐Ÿ“ AuctionCommandService.java

๐Ÿ“ AuctionRepositoryPort.java

๐Ÿ“ AuctionRepositoryAdapter.java

๐Ÿ“ AuctionRepository.java


Thoughts

์ด์ „๊นŒ์ง€ ๋‹จ์ผ๋ชจ๋“ˆ๋กœ ๊ฐœ๋ฐœ์„ ํ•ด์™”์—ˆ๊ณ  ๋ฉ€ํ‹ฐ๋ชจ๋“ˆ์ด ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ด๋ฒˆ์— ์ฒ˜์Œ ์•Œ์•˜๋‹ค. ์ด์ „๊นŒ์ง€ ๋‹จ์ผ๋ชจ๋“ˆ๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๋ฉด์„œ ๋””๋ ‰ํ† ๋ฆฌ์™€ ํด๋ž˜์Šค์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚  ๋•Œ๋งˆ๋‹ค ๊ด€๋ฆฌํ•˜๊ณ  ์›ํ•˜๋Š” ํŒŒ์ผ ์ฐพ๊ธฐ๊ฐ€ ์–ด๋ ค์› ์—ˆ๋‹ค.
์ด๋ฒˆ ๋ฉ€ํ‹ฐ๋ชจ๋“ˆ๋กœ ๋ณ€๊ฒฝํ•œ ํ›„ ๊ฐœ๋ฐœ์„ ์ญ‰ ๋Œ€๋žต 2๊ฐœ์›” ๊ฐ€๊นŒ์ด ์ง„ํ–‰ํ•ด ๋ณด์•˜๋Š”๋ฐ, ํ™•์‹คํžˆ ์›ํ•˜๋Š” ํŒŒ์ผ ์ฐพ๊ธฐ๊ฐ€ ๋‹จ์ผ๋ชจ๋“ˆ์ผ ๋•Œ๋ณด๋‹ค ํ›จ์”ฌ ์ˆ˜์›”ํ•ด์กŒ๋‹ค.
๋˜ ๋ชจ๋“ˆ์„ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋‚˜๋ˆˆ ๋•์— build ์‹œ๊ฐ„ ๋˜ํ•œ ๋‹จ์ถ•๋œ ๋Š๋‚Œ์ด ๋“ค์—ˆ๋‹ค.
์•ž์œผ๋กœ ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ํ™•์žฅํ•ด ๋‚˜๊ฐ€๋Š” ๋ฐ์— ์žˆ์–ด์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์ „๋ณด๋‹ค ์–ด๋ ต์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™๋‹ค.

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

๋งˆ์ง€๋ง‰์œผ๋กœ ํ—ฅ์‚ฌ๊ณ ๋‚  ์•„ํ‚คํ…์ฒ˜ ์ค‘ "๋„๋ฉ”์ธ๊ณผ ์—”ํ‹ฐํ‹ฐ"๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๋‚ด์šฉ์ด ์žˆ์—ˆ๋‹ค. ๋„๋ฉ”์ธ๊ณผ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ฐ์ดํ„ฐ ์ €์žฅ ๋กœ์ง์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ™•์žฅ์„ฑ์ด ํ–ฅ์ƒํ•œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.
์ด๋ฅผ ์ฒ˜์Œ์— ์ ์šฉํ•ด ๋ณด์•˜์ง€๋งŒ, ์‚ฌ์‹ค ์ด๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ์–ป๋Š” ์ด์ ๋ณด๋‹ค ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ๋งŒ ๋Š˜์–ด๋‚˜์„œ ์–ป๋Š” ๋‹จ์ ์ด ํฌ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด Update ๊ด€๋ จ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ, ๋„๋ฉ”์ธ๊ณผ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด "๋”ํ‹ฐ ์ฒดํ‚น"์„ ํ†ตํ•ด ๊ตณ์ด Save๋ฅผ ๋‹ค์‹œ ํ•  ํ•„์š”๊ฐ€ ์—†์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋„๋ฉ”์ธ๊ณผ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌํ•œ๋‹ค๋ฉด, ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๋ฅผ JPA๋ฅผ ํ†ตํ•ด ์ฐพ๊ณ , ์ฐพ์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋„๋ฉ”์ธ์œผ๋กœ ๋ณ€๊ฒฝ, ๋„๋ฉ”์ธ์„ ์ˆ˜์ •, ๋„๋ฉ”์ธ์„ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€๊ฒฝ, ์—”ํ‹ฐํ‹ฐ๋ฅผ JPA๋ฅผ ํ†ตํ•ด ๋‹ค์‹œ ์ €์žฅํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์ณ์•ผ ํ–ˆ๋‹ค.
๊ทธ๋ž˜์„œ "๋„๋ฉ”์ธ๊ณผ ์—”ํ‹ฐํ‹ฐ" ๋ถ„๋ฆฌ๋Š” ์ ์šฉํ•˜์ง€ ์•Š๊ณ  ์ด ๊ธ€์˜ "๐Ÿ”ฅTroubleShooting๐Ÿ”ฅ"์„ ํ•ด๊ฒฐํ–ˆ๋‹ค.


profile
๐Ÿ’ป ๐Ÿ’ป ๐Ÿ’ป

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด