Project - Wedge ๐
๐ Wedge ํ๋ก์ ํธ ํ๊ณ โ 2์ฃผ ๋ง์ ์จ๋ฉ ๋งค์นญ ํ๋ซํผ ๋ง๋ค๊ธฐ
2026.06.11 ~ 06.24 | ํ ํ๋ก์ ํธ | 4์ธ ๊ฐ๋ฐ
ํ๋ก์ ํธ ์๊ฐ
Wedge๋ ์๋น๋ถ๋ถ(CLIENT)์ ์จ๋ฉ ์ ๋ฌธ ํ๋ฆฌ๋์(FREELANCER)๋ฅผ ์ฐ๊ฒฐํ๋ ๋งค์นญ ํ๋ซํผ์ด๋ค.
์จ๋ฉํ ํจํค์ง์ ๋ฌถ์ฌ ์์ผ๋ฉด ๋น์ธ๊ณ ์ ํ์ง๋ ์ข๋ค. ๋ฐ๋๋ก ํ๋ฆฌ๋์ ์ ์ฅ์์๋ ์ค๋ ฅ์ด ์์ด๋ ํ๋ณด ์ฑ๋์ด ์์ผ๋ฉด ์ผ๊ฐ์ ๋ชป ์ฐพ๋๋ค. Wedge๋ ์ด ๋์ ์ง์ ์ฐ๊ฒฐํ๋ ๊ตฌ์กฐ๋ค. ํต์ฌ ์ฐจ๋ณ์ ์ ์ญ๊ฒฝ๋งค ๋ฐฉ์: ์๋น๋ถ๋ถ๊ฐ ๊ตฌ์ธ๊ธ์ ์ฌ๋ฆฌ๋ฉด ํ๋ฆฌ๋์๊ฐ ์ง์ ์ ์์๋ฅผ ๋ด๊ณ , ๋ถ๋ถ๊ฐ ๋ง์์ ๋๋ ์ ์์ ์๋ฝํ๋ฉด ์์ฝ์ด ์๋ ์์ฑ๋๋ค.
๊ธฐ๋ฅ ๋ฒ์๊ฐ ๊ฝค ๋์๋ค. ์ธ์ฆ, ํ๋กํ, ํฌํธํด๋ฆฌ์ค, ๋ถ๋งํฌ, ์์ฝ, ์ค์๊ฐ ์ฑํ , ๋ฆฌ๋ทฐ, ์ปค๋ฎค๋ํฐ, ๊ตฌ์ธ/์ ์, AI ์ฑ๋ด, CI/CD๊น์ง โ ์ด๊ฑธ 2์ฃผ ์์ 4๋ช ์ด ์์ฑํด์ผ ํ๋ค.
๋ฐฐํฌ URL: wedge-tawny.vercel.app
์์ฐ ์์: streamable.com/6dklaq
ํ์๊ณผ ์ญํ ๋ถ๋ด
| ์ด๋ฆ | ๋ด๋น |
|---|---|
| ์คํ๋น | ์ฐ(๋ถ๋งํฌ), ์ ๋ฌธ๊ฐ ํ์ API, ์ถ์ฒ ์บ๋ฌ์ (Redis ์บ์ฑ), AI ๊ฒฌ์ ์ฑ๋ด |
| ์ ๋ฏผํ (๋) | ํ์ ์ธ์ฆ(JWTยทOAuth2ยท์ด๋ฉ์ผ), ๊ตฌ์ธ/์ ์ ์์คํ , ์ปค๋ฎค๋ํฐ, CI/CD, AWS ๋ฐฐํฌ |
| ์ด์ฐฝ๋ฏผ | ์์ฝ ์์คํ , ์ค์๊ฐ ์ฑํ (WebSocketยทSTOMP), ๋ฆฌ๋ทฐ ๊ธฐ๋ฅ |
| ์ด๋ฏผ์ | ํ๋ฆฌ๋์ ํ๋กํ, ํฌํธํด๋ฆฌ์ค(Cloudflare R2), ๋ง์ดํ์ด์ง UX, ๋์์ธ ์์คํ |
๋ด๊ฐ ๋งก์ ํํธ โ ๊ธฐ์ ์ ๊ฒฐ์ ๋ค
1. ์ธ์ฆ ์์คํ : JWT + RTR + OAuth2
์ธ์ฆ์ ๋๋ถ๋ถ์ ๊ธฐ๋ฅ์ด ์์กดํ๋ ๋ฟ๋ฆฌ๋ผ์ ๊ฐ์ฅ ๋จผ์ , ๊ฐ์ฅ ๊ผผ๊ผผํ๊ฒ ์ค๊ณํ๋ค.
RTR(Refresh Token Rotation)
์ผ๋ฐ JWT ๊ตฌ์กฐ์์ Refresh Token์ด ํ์ทจ๋๋ฉด, ๋ง๋ฃ๋ ๋๊น์ง ๊ณต๊ฒฉ์๊ฐ ๊ณ์ ์ธ ์ ์๋ค. RTR์ ์ ์ฉํ๋ฉด ํ ํฐ์ ์ฌ์ฉํ ๋๋ง๋ค ์ ํ ํฐ์ผ๋ก ๊ต์ฒด๋๋ฏ๋ก, ํ์ทจ ํผํด๋ฅผ ์ต์ํํ ์ ์๋ค.
๊ตฌํ ๋ฐฉ์์ ๊ฐ๋จํ๋ค. Redis์ memberId๋ฅผ ํค๋ก Refresh Token 1๊ฐ๋ง ์ ์งํ๋ค. save()๋ฅผ ํธ์ถํ๋ฉด ๊ธฐ์กด ํ ํฐ์ด ๋ฎ์ด์จ์ง๋ฉด์ ์๋์ผ๋ก ๋ฌดํจํ๋๋ค. ๋๊ฐ ๋จผ์ ์ฐ๋ ๋๋จธ์ง ํ์ชฝ์ ์ฐจ๋จ๋๋ค.
refreshTokenRepository.save(RefreshToken.builder()
.memberId(memberId)
.token(newRefreshToken) // upsert โ ๊ธฐ์กด ํ ํฐ ์๋ ๋ฌดํจํ
.build());์ด๋ฉ์ผ ์ธ์ฆ ์ํ ๋จธ์
Redis ํค๋ฅผ ๋ ๊ฐ๋ก ๋ถ๋ฆฌํ๋ค: ์ธ์ฆ ์ฝ๋(TTL 5๋ถ)์ ์๋ฃ ํ๋๊ทธ(TTL 30๋ถ). ์ญํ ๊ณผ ๋ง๋ฃ ์๊ฐ์ด ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ํ๋๋ก ํฉ์น ์ ์๋ค. ์ธ์ฆ ์ฝ๋ ๊ฒ์ฆ ์ฆ์ ์ญ์ ํด์ 1ํ์ฉ์ ๋ณด์ฅํ๊ณ , ํ์๊ฐ์ ์๋ฃ ์ ํ๋๊ทธ๋ ์ญ์ ํด์ ์ค๋ณต ๊ฐ์ ์ ์ฐจ๋จํ๋ค. DB ๋์ Redis๋ฅผ ์ด ์ด์ ๋ TTL ๋์ ๋ง๋ฃ ๋ฐฐ์น ์์ ์ด ํ์ ์๊ณ , ์กฐํ๋ ~1ms๋ก ๋น ๋ฅด๊ธฐ ๋๋ฌธ์ด๋ค.
OAuth2 (Google + Kakao) ํตํฉ
๊ตฌ๊ธ๊ณผ ์นด์นด์ค๋ JSON ์๋ต ๊ตฌ์กฐ๊ฐ ๋ค๋ฅด๋ค. providerId, email, name์ ๊ฒฝ๋ก๊ฐ ์ ๊ฐ๊ฐ์ด๋ค. OAuth2MemberService.loadUser()์์ provider๋ณ ํ์ฑ๋ง ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํ๊ณ , ๊ทธ ์ดํ๋ ๋์ผํ Member ์ํฐํฐ๋ก ํตํฉํ๋ค. ํ๋ก ํธ์๋๋ ๋ก๊ทธ์ธ ๊ฒฝ๋ก์ ์๊ด์์ด JWT ํ๋๋ก๋ง ํต์ ํ๋ค.
2. Mixed Content & Caddy ๋ฆฌ๋ฒ์ค ํ๋ก์
๋ฐฐํฌ ์ง์ ์ ์๊ฐ์ง ๋ชปํ ๋ฌธ์ ๊ฐ ํฐ์ก๋ค. Vercel(HTTPS)์์ AWS EC2(HTTP, 8080) API๋ฅผ ํธ์ถํ๋ ๋ธ๋ผ์ฐ์ ๊ฐ Mixed Content ์ ์ฑ ์ผ๋ก ์ ๋ถ ์ฐจ๋จํ๋ค.
๋ธ๋ผ์ฐ์ โ Vercel(HTTPS) โ AWS EC2:8080(HTTP) โ ์ฐจ๋จ!
ํด๊ฒฐ์ฑ ์ Caddy์๋ค.
api.wedge.o-r.kr {
reverse_proxy localhost:8080
}
์ด ๋ ์ค์ด ์ ๋ถ๋ค. ๋๋ฉ์ธ์ ์ ์ผ๋ฉด Caddy๊ฐ Let's Encrypt์์ ์ธ์ฆ์๋ฅผ ์๋ ๋ฐ๊ธํ๊ณ , ๋ง๋ฃ 30์ผ ์ ์ ์์์ ๊ฐฑ์ ํ๋ค.
๋ธ๋ผ์ฐ์ โ Vercel(HTTPS) โ Caddy(HTTPS, 443) โ Spring Boot(HTTP, 8080)
Spring Boot์ SSL์ ์ง์ ๋ถ์ด๋ฉด keystore ์ค์ , ์ธ์ฆ์ ๊ฐฑ์ ์ ์ฌ์์์ด ํ์ํ๋ฐ, Caddy๋ก ๋ถ๋ฆฌํ๋ฉด ๊ทธ ๋ณต์กํจ์ด ์ฌ๋ผ์ง๋ค. 2์ฃผ์ง๋ฆฌ ํ๋ก์ ํธ์์ ์ธํ๋ผ์ ์ธ ์ ์๋ ์๊ฐ์ ์ ํ์ ์ด์๊ณ , Caddy ๋๋ถ์ ์ธํ๋ผ ์ธํ ์๊ฐ์ ํฌ๊ฒ ์ค์ผ ์ ์์๋ค.
| Caddy | Nginx | |
|---|---|---|
| SSL ์ธ์ฆ์ | ์๋ ๋ฐ๊ธ + ์๋ ๊ฐฑ์ | certbot ๋ณ๋ ์ค์น, cron ๋ฑ๋ก |
| ์ค์ ํ์ผ | 2์ค | 20์ค+ |
3. CI/CD ํ์ดํ๋ผ์ธ
dev ๋ธ๋์น์ push๋๋ฉด CI๊ฐ ๋๊ณ , main์ ๋จธ์ง๋๋ฉด ์๋ ๋ฐฐํฌ๋๋ค.
CI: GitHub Actions๊ฐ MySQL 8.0 + Redis ์๋น์ค ์ปจํ ์ด๋๋ฅผ ์ง์ ๋์์ ํตํฉ ํ ์คํธ๋ฅผ ๋๋ฆฐ๋ค. Mock์ด ์๋๋ผ ์ค์ DB์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฐ๋ค. ํ ์คํธ๊ฐ ํ๋๋ผ๋ ์คํจํ๋ฉด PR ๋จธ์ง๊ฐ ์ฐจ๋จ๋๋ค.
CD: bootJar ๋น๋ โ Docker ์ด๋ฏธ์ง ๋น๋ โ Docker Hub ํธ์(latest + commit SHA ํ๊ทธ) โ SSH๋ก EC2 ์ ์ โ ์ปจํ
์ด๋ ๊ต์ฒด.
EC2์์ ์ง์ Gradle ๋น๋ํ๋ฉด t2.micro(๋ฉ๋ชจ๋ฆฌ 1GB)๊ฐ OOM์ผ๋ก ์ฃฝ๋๋ค. ๊ทธ๋์ GitHub Actions์์ ๋น๋ํด์ ์์ฑ๋ ์ด๋ฏธ์ง๋ง EC2๋ก ๋น๊ฒจ์ค๋ ๊ตฌ์กฐ๋ฅผ ํํ๋ค. commit SHA ํ๊ทธ๋ฅผ ๋ฐ๋ก ๋ถ์ฌ๋๋ ์ด์ ๋ ๋กค๋ฐฑ์ ์ํด์๋ค. latest๋ง ์์ผ๋ฉด ์ด์ ๋ฒ์ ์ผ๋ก ๋์๊ฐ๊ธฐ ์ด๋ ต๋ค.
Docker ๋ฉํฐ ์คํ ์ด์ง ๋น๋๋ ์ ์ฉํ๋ค. Stage 1(JDK + Gradle)์์ ๋น๋ํ๊ณ , Stage 2(JRE๋ง)์์ jar๋ฅผ ๋ณต์ฌํด ์คํํ๋ค. ์ต์ข ์ด๋ฏธ์ง์ JDK์ ์์ค์ฝ๋๊ฐ ๋ค์ด๊ฐ์ง ์์์ ์ด๋ฏธ์ง๊ฐ ~300MB ๊ฐ๋ฒผ์์ง๋ค.
๋ฐฐํฌ ํ๋ฆ ์ ์ฒด:
์กฐ์ง ๋ ํฌ dev โ main ๋จธ์ง
โ (ํฌํฌ ์๋ ๋๊ธฐํ)
๊ฐ์ธ ํฌํฌ main ์
๋ฐ์ดํธ
โ (CD ํธ๋ฆฌ๊ฑฐ)
GitHub Actions: ๋น๋ โ Docker Hub
โ (SSH)
AWS EC2: pull โ ์ปจํ
์ด๋ ๊ต์ฒด โ ์๋ฃ
4. ๊ตฌ์ธ/์ ์ ์์คํ
๊ตฌ์ธ๊ธ์์ ์ ์์ ์๋ฝ๊น์ง ์ด์ด์ง๋ ํ๋ฆ์ ์ค๊ณํ๋ค. ์ ์์๊ฐ ์๋ฝ๋๋ฉด ์์ฝ์ด ์๋ ์์ฑ๋๋ค. DB ์ ์ฝ๋ ๊ผผ๊ผผํ๊ฒ ๊ฑธ์๋ค: ๊ตฌ์ธ๊ธ ๋์ ๋ฑ๋ก ์ต๋ 3๊ฑด, ์ ์์ ๋์ ์ ์ถ ์ต๋ 5๊ฑด. ๋ง๊ฐ๋ ๊ตฌ์ธ๊ธ์ ์์ ์ฐจ๋จ, proposals ํ
์ด๋ธ์ (recruit_post_id, freelancer_profile_id) ๋ณตํฉ UNIQUE ํค๋ก ์ค๋ณต ์ ์์ ๋ง์๋ค.
5. ์ปค๋ฎค๋ํฐ ๊ฒ์ํ
REVIEW/TIP ์นดํ
๊ณ ๋ฆฌ๋ก ๋ถ๋ฆฌ๋ ์ปค๋ฎค๋ํฐ ๊ฒ์ํ์ ๊ตฌํํ๋ค. ์ํํธ ์ญ์ (is_deleted)๋ฅผ ์ ์ฉํด์ ๋ฐ์ดํฐ๋ ๋จ๊ธฐ๊ณ ๋
ธ์ถ๋ง ๋๋ ๊ตฌ์กฐ๋ค. ํ๋ฐ์ ์ด๋ฏธ์ง ์ฒจ๋ถ ๊ธฐ๋ฅ๊ณผ ํ๋ฆฌ๋์ ์ธ๊ธ ๊ธฐ๋ฅ๊น์ง ์ถ๊ฐ๋๋ค.
ํ ํ์ : ์ ๋ ๊ฒ๋ค
Git ์ ๋ต์ด ๋จ์ํ๊ณ ๋ช
ํํ๋ค. dev ๋ธ๋์น์์ ๊ธฐ๋ฅ ๋ธ๋์น๋ฅผ ๋ฐ๊ณ , PR์ ํตํด ํฉ์ณค๋ค. CI๊ฐ ๋ถ์ด ์์ผ๋ ๊นจ์ง ์ฝ๋๊ฐ dev์ ์์ด๋ ์ผ์ด ๊ฑฐ์ ์์๋ค.
์ญํ ๋ถ๋ฆฌ๊ฐ ๊น๋ํ๋ค. ๋ฐฑ์๋ 4๋ช ์ด ๋๋ฉ์ธ ๋จ์๋ก ๋๋ ์ ์์ ํ๋๋ฐ, ์ธํฐํ์ด์ค(API ์คํ)๋ง ๋ง์ถ๋ฉด ์๋ก ํฌ๊ฒ ์ถฉ๋ํ์ง ์์๋ค. ํ๋ก ํธ๋ ์ด๋ฏผ์ ๋์ด ๋์์ธ ์์คํ ๊ณผ ๋ง์ดํ์ด์ง๋ฅผ ๋ด๋นํ๋ฉด์ UI ์ผ๊ด์ฑ์ ์ก์์คฌ๋ค.
Mock ์์ด ํตํฉ ํ ์คํธ. CI์์ ์ค์ MySQL๊ณผ Redis๋ฅผ ๋์์ ํ ์คํธํ๊ธฐ ๋๋ฌธ์ "๋ก์ปฌ์์๋ ๋๋๋ฐ ์๋ฒ์์ ์ ๋จ" ๊ฐ์ ์ํฉ์ด ํจ์ฌ ์ค์๋ค.
์์ฌ์ด ๊ฒ๋ค
t2.micro์ ํ๊ณ. ๋ฉ๋ชจ๋ฆฌ 1GB๋ก MySQL + Redis + Spring Boot๋ฅผ ๋์์ ๋๋ฆฌ๋ ๊ฐ๋ OOM์ด ๋ฌ๋ค. Swap 2GB๋ฅผ ์ถ๊ฐํด์ ๊ฒจ์ฐ ๋ฒํ ผ๋๋ฐ, ์ค์ ์๋น์ค๋ผ๋ฉด ์ธ์คํด์ค ์คํ์ ์ฌ๋ ค์ผ ํ๋ค.
ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง. CI์์ ํตํฉ ํ ์คํธ๋ฅผ ๋๋ฆฌ๊ธด ํ์ง๋ง, ์์ฑ๋ ํ ์คํธ์ ์์ด ์ถฉ๋ถํ์ง ์์๋ค. ๋น ๋ฅด๊ฒ ๊ธฐ๋ฅ์ ๋ง๋๋ ๋ฐ ์ง์คํ๋ค ๋ณด๋ ์ฃ์ง ์ผ์ด์ค ํ ์คํธ๊ฐ ๋ถ์กฑํ๋ค.
AI ๊ธฐ๋ฅ๊ณผ ์ฑํ ์ด ํ์์๋ก ๋ฐ๋ ธ๋ค. ์๋ MVP ์ฐ์ ์์์์ ํ์์๋ ๊ธฐ๋ฅ๋ค์ด ๋ง์ง๋ง์ ๋ถ์๋ค. ์์ฑ์ ๋์ง๋ง ๋ ๋ค๋ฌ์ ์๊ฐ์ด ์์๋ค.
๋ฐฐํฌ ์๋ํ์ ๋นํ. ์กฐ์ง ๋ ํฌ โ ๊ฐ์ธ ํฌํฌ ๋๊ธฐํ๋ฅผ GitHub Actions๋ก ์๋ํํ๋๋ฐ, ๊ฐํน sync๊ฐ ๋ฆ๊ฑฐ๋ ์คํจํ๋ ์ผ์ด์ค๊ฐ ์์๋ค. ๋ ๊ฒฌ๊ณ ํ ํ์ดํ๋ผ์ธ์ด ํ์ํ๋ค.
๋ฐฐ์ด ๊ฒ
2์ฃผ๋ ์๊ฐ๋ณด๋ค ํจ์ฌ ์งง๋ค. ๊ธฐ๋ฅ์ ์ฒ์๋ถํฐ ์๋ฒฝํ๊ฒ ๋ง๋ค๋ ค๊ณ ํ๋ฉด ์๋ฌด๊ฒ๋ ์์ฑ๋์ง ์๋๋ค. MVP ์ฐ์ ์์๋ฅผ ์ ํ๊ณ , ํต์ฌ์ด ์๋ ๊ฒ์ ๊ณผ๊ฐํ๊ฒ ๋ค๋ก ๋ฏธ๋ฃจ๋ ํ๋จ์ด ์ค์ํ๋ค.
์ธ์ฆ ์์คํ ์ ํ๋ก์ ํธ ์ด๋ฐ์ ์์ฑ๋ ์๊ฒ ์ค๊ณํด๋๊ธธ ์ํ๋ค. ๋ชจ๋ ๊ธฐ๋ฅ์ด ์ธ์ฆ์ ์์กดํ๊ธฐ ๋๋ฌธ์, ์ด๊ฒ ๋ถ์์ ํ๋ฉด ํ ์ ์ฒด๊ฐ ํ๋ค๋ฆฐ๋ค.
Caddy๋ ์ ๋ง ์ข์ ๋๊ตฌ๋ค. ๋จ, ACME ์ฑ๋ฆฐ์ง๋ฅผ ์ํด 80ํฌํธ๊ฐ ์ด๋ ค ์์ด์ผ ํ๋ค๋ ๊ฑธ ์ฒ์์ ๋ชฐ๋ผ์ ์ฝ์งํ๋ค.
CI/CD๋ฅผ ์ฒ์๋ถํฐ ๊ตฌ์ฑํด๋ ๊ฒ ํ ์ ์ฒด ์์ฐ์ฑ์ ํฌ๊ฒ ๊ธฐ์ฌํ๋ค. ์๋์ผ๋ก ๋ฐฐํฌํ๋๋ผ ์๊ฐ์ ์ฐ์ง ์์๋ ๋๊ณ , ํ ์คํธ๊ฐ ์๋์ผ๋ก ๋์๊ฐ๋ ์๋ก ์ฝ๋๋ฅผ ํฉ์น๋ ๋ฐ ๋ ๋ถ์ํ๋ค.
๋ง๋ฌด๋ฆฌ
2์ฃผ ์์ ์ด ์ ๋ ๊ท๋ชจ์ ์๋น์ค๋ฅผ ์์ฑํ ๊ฒ ์ ๊ธฐํ๊ฒ ๋๊ปด์ง๋ค. ํ์ ๊ฐ์๊ฐ ๋งก์ ์์ญ์ ๋๊น์ง ์ฑ ์์ก๊ณ , ๋๋ถ์ ๋ฐฐํฌ URL์ด ์ค์ ๋ก ๋์๊ฐ๋ค.
๋ค์์๋ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ฒ์๋ถํฐ ์ฑ๊ธฐ๋ฉด์ ๋ง๋ค๊ณ ์ถ๋ค.