HOME
home
Team
home

MoodHolic

ย ๋‚ด๊ฐ€ ๊ธฐ์—ฌํ•œ ๋ถ€๋ถ„

โ€ข
OAuth2๋ฅผ ์ด์šฉํ•˜์—ฌ Google, Naver, Kakao, GitHub ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„
โ€ข
OpenAI API๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ ์ผ๊ธฐ๋ฅผ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋„๋กํ•˜์—ฌ ์ผ๊ธฐ ๋ถ„์„์„ํ•ด์„œ ์ ์ˆ˜๋กœ ๋„์ถœ ์‹œํ‚ค๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„
โ€ข
JWT๋ฅผ ํ™œ์šฉํ•œ ์ธ์ฆ ์ ˆ์ฐจ๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ , Redis์— ํ† ํฐ์„ ์ €์žฅํ•˜์—ฌ ๋ณด์•ˆ์„ฑ์„ ๊ฐ•ํ™”
โ€ข
GitHub์„ ํ†ตํ•œ ํ˜•์ƒ ๊ด€๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, Git Flow ์ „๋žต, ์ปค๋ฐ‹ ๋ฐ PR ์ปจ๋ฒค์…˜, ์ฝ”๋“œ ์ปจ๋ฒค์…˜์„ ๋„์ž…ํ•˜์—ฌ ์ฝ”๋“œ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ณ  ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€
โ€ข
์‚ฌ์šฉ์ž๋“ค์ด ์–ด๋Š ํ”Œ๋žซํผ์—์„œ ์ ‘์†ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด React Native์™€ Expo๋ฅผ ํ™œ์šฉํ•˜์—ฌ WebApp์„ ๊ฐœ๋ฐœ
โ€ข
์ˆ˜ํ–‰ํ•  ์ž‘์—…์„ ๊ณ„ํšํ•˜๊ณ  ๋ชฉํ‘œ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด Sprint ๋„์ž…ํ•˜์—ฌ 1์ฃผ ๋‹จ์œ„๋กœ Sprint ์ž‘์—…์„ ์ง„ํ–‰
ํ—ค๋”
๋กœ๊ทธ์ธ ํ›„ ๋‹ค์ด์–ด๋ฆฌ
๋กœ๊ทธ์ธ ํŽ˜์ด์ง€
๋กœ๊ทธ์ธ ํ›„ ๋งˆ์ดํŽ˜์ด์ง€
๋งˆ์ดํŽ˜์ด์ง€ โ€˜๋‚ด ๋‹ค์ด์–ด๋ฆฌโ€™ ํ†ต๊ณ„ ํ™”๋ฉด

ย ์‚ฌ์šฉ ๊ธฐ์ˆ 

โ€ข
DataBase
โ—ฆ
MariaDB / Redis
โ€ข
BackEnd
โ—ฆ
Java / Spring Boot / Spring Data JPA / Spring Security / JWT / Google Storage
โ€ข
API
โ—ฆ
Kakao Login / Google Login / OpenAI / Swagger / OpenWeatherMap
โ€ข
Software Architecture Pattern
โ—ฆ
Monolithic Architecture
โ€ข
FrontEnd
โ—ฆ
HTML / CSS / JavaScript / Vue.js / VueX / React Native
โ€ข
DevOps
โ—ฆ
Docker / Jenkins / Kubernetes / AWS EC2
โ€ข
Collaboration
โ—ฆ
GitHub / Slack / Notion / Figma / Miro

System Architecture

MoodHolic System Architecture

ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… 1

๋ฌธ์ œ ๋ฐฐ๊ฒฝ

Spring Boot ๊ธฐ๋ฐ˜์˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ OpenAPI ์š”์ฒญ ์ค‘, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ URL์„ ์š”์ฒญํ–ˆ์„ ๋•Œ java.lang.IllegalArgumentException: Invalid character found in the request target ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
์ด๋Š” Tomcat ์„œ๋ฒ„์˜ ๊ธฐ๋ณธ ์„ค์ •์—์„œ ํŠน์ • ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์•„ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” application.yml์—์„œ UTF-8 ์ธ์ฝ”๋”ฉ์„ ๊ฐ•์ œ๋กœ ์ ์šฉํ•˜๋ ค ํ–ˆ์œผ๋‚˜, ์ด ๋ฐฉ๋ฒ•์€ ๋ฌธ์ œ ํ•ด๊ฒฐ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ URL์€ Tomcat ์„œ๋ฒ„์˜ ๊ธฐ๋ณธ ์„ค์ •๊ณผ ์ถฉ๋Œํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด, Tomcat ์„œ๋ฒ„์˜ ์„ค์ •์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜์—ฌ ํŠน์ • ํŠน์ˆ˜ ๋ฌธ์ž๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ์กฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. TomcatServletWebServerFactory ํด๋ž˜์Šค๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜๊ณ , relaxedQueryChars ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ <, >, [, ], ^, `, {, |, } ๋“ฑ์˜ ํŠน์ˆ˜ ๋ฌธ์ž๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ์„  ๊ฒฐ๊ณผ

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

ํ•ด๋‹น ๊ฒฝํ—˜์„ ํ†ตํ•ด ์•Œ๊ฒŒ ๋œ ์ 

์„œ๋ฒ„ ์„ค์ •์˜ ์ค‘์š”์„ฑ๊ณผ ๋งž์ถคํ˜• ์„ค์ •์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์•ˆ์ •์„ฑ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ๋‹จ์ˆœํ•œ ์„ค์ • ๋ณ€๊ฒฝ์œผ๋กœ ๋ณต์žกํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค.
application.yml์—์„œ ๊ฐ•์ œ๋กœ ์ธ์ฝ”๋”ฉ
Config ํŒจํ‚ค์ง€์— TomcatWebCustomCofig Class ์ถ”๊ฐ€ํ•˜์—ฌ ํ—ˆ์šฉ ํŠน์ˆ˜๋ฌธ์ž ์„ค์ •

ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… 2

๋ฌธ์ œ ๋ฐฐ๊ฒฝ

Spring Boot ๊ธฐ๋ฐ˜์˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ API ์‘๋‹ต์— ํ•œ๊ธ€ ๋ฌธ์ž๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ‘œ์‹œ๋˜์ง€ ์•Š๊ณ , ๋ฌผ์Œํ‘œ(???)๋กœ ๋Œ€์ฒด๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Spring ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ธฐ๋ณธ ์ธ์ฝ”๋”ฉ ์„ค์ •์ด ISO-8859-1๋กœ ๋˜์–ด ์žˆ์–ด, ํ•œ๊ธ€๊ณผ ๊ฐ™์€ ๋‹ค๊ตญ์–ด ๋ฌธ์ž๋ฅผ ์ œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์—์„œ ๋น„๋กฏ๋œ ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Spring์˜ WebMvcConfigurer๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜์—ฌ StringHttpMessageConverter๋ฅผ UTF-8 ์ธ์ฝ”๋”ฉ์œผ๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ํ†ตํ•ด ์‘๋‹ต ๋ฉ”์‹œ์ง€๊ฐ€ ํ•œ๊ธ€๋กœ ์ œ๋Œ€๋กœ ์ธ์ฝ”๋”ฉ๋˜์–ด ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค. UTF-8 ์ธ์ฝ”๋”ฉ์ด ์šฐ์„  ์ ์šฉ๋˜์–ด ํ•œ๊ธ€ ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด StringHttpMessageConverter๋ฅผ ์ปจ๋ฒ„ํ„ฐ ๋ชฉ๋ก์˜ ๊ฐ€์žฅ ์•ž์— ๋‘์–ด ๋‹ค๋ฅธ ์ปจ๋ฒ„ํ„ฐ๋ณด๋‹ค ๋จผ์ € ์‹คํ–‰๋˜๋„๋ก ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ์„  ๊ฒฐ๊ณผ

์ด ์„ค์ •์„ ํ†ตํ•ด ํ•œ๊ธ€ ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๊ณ , API ์‘๋‹ต์—์„œ ํ•œ๊ธ€ ๋ฌธ์ž๊ฐ€ ์˜จ์ „ํžˆ ํ‘œ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ „์—๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋ฌผ์Œํ‘œ(???)๋กœ ๋ณด์˜€๋˜ ํ•œ๊ธ€ ๋ฉ”์‹œ์ง€๋“ค์ด ์ •ํ™•ํžˆ ์ „๋‹ฌ๋˜์—ˆ์œผ๋ฉฐ, ๋˜ํ•œ, ์ด๋Ÿฌํ•œ ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •์—์„œ ์–ป์€ ๊ฒฝํ—˜์„ ํ†ตํ•ด ๋‹ค๋ฅธ ์–ธ์–ด ํ™˜๊ฒฝ์—์„œ๋„ ๋ฌธ์ž ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ๋ฅผ ๋ณด๋‹ค ์‹ ์†ํ•˜๊ณ  ํšจ๊ณผ์ ์œผ๋กœ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋Š” ์—ญ๋Ÿ‰์„ ๊ฐ–์ถ”๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•ด๋‹น ๊ฒฝํ—˜์„ ํ†ตํ•ด ์•Œ๊ฒŒ ๋œ ์ 

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

๐Ÿซกย ํšŒ๊ณ 

โ€œํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋ฏฟ์œผ๋ฉด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์‹ ๋…"
ํ”„๋กœ์ ํŠธ์—์„œ ์ €๋Š” Oauth 2.0, OpenAI API, Redis, React Native์™€ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๊ธฐ์ˆ ์„ ์ ‘ํ•˜๊ณ , ์‹ค์ œ๋กœ ์ ์šฉํ•ด๋ณด๋ฉด์„œ ๋งŽ์€ ์„ฑ์žฅ์„ ์ด๋ค˜์Šต๋‹ˆ๋‹ค. โ€œํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ํ•  ๊ฒƒ์ด๊ณ , ์•ˆ๋˜๋ฉด ๋˜๊ฒŒ ํ•œ๋‹คโ€๋Š” ์ฒ ํ•™์„ ํ†ตํ•ด ์–ด๋ ค์šด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ , ๊ธฐ์ˆ ์  ํ•œ๊ณ„๋ฅผ ๊ทน๋ณตํ•ด ๋‚˜๊ฐ”์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ ํ•ด๊ฒฐ ๋Šฅ๋ ฅ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ ๊ทน์ ์ธ ์ž์„ธ๋ฅผ ๋ฐฐ์šฐ๋ฉฐ, ์•ž์œผ๋กœ๋„ ๋Š์ž„์—†์ด ๋ฐœ์ „ํ•˜๊ณ  ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.