๋ชฉํ ๋ฑ๋ก/์์ /์ญ์ ๊ธฐ๋ฅ
Goal
์ํฐํฐ์ ๋ด์ฉ
, ์์์ผ
, ๋ง๊ฐ์ผ
, ๊ณต๊ฐ ๋ฒ์(OpenScope)
๋ฅผ ํจ๊ป ์
๋ ฅํจ.@DateTimeFormat
์ ํตํด ๋ ์ง ํ์์ ๋ณํํ๊ณ , ์ฐ๊ด๋ ๊ณต๊ฐ ๋ฒ์๋ ์ธ๋ ํค ๊ธฐ๋ฐ์ผ๋ก OpenScope
ํ
์ด๋ธ๊ณผ ์กฐ์ธ ์ฒ๋ฆฌ.UserAchiv
๋ฐ์ดํฐ๋ ํจ๊ป ์ฒ๋ฆฌ๋๋๋ก ์ค๊ณ.๋ชฉํ ๋ฌ์ฑ ์ฌ๋ถ ๊ธฐ๋ก (์ผ๋ณ ์ด์ง ์ํ ์ ์ฅ)
GoalStatus
ํ
์ด๋ธ์ ๋ ์ง
์ is_success=true
์ํ(Boolean)๊ฐ ์ ์ฅ๋จ.false
๋ null
์ ๋์ผํ๊ฒ ๋ฏธ๋ฌ์ฑ(ํ์)์ผ๋ก ํ์.is_success=false
๋ก ์
๋ฐ์ดํธ๋จ.findTodayGoalStatus(goal, date)
๋ก ์ค๋ ๊ธฐ๋ก ์กด์ฌ ์ฌ๋ถ ์กฐํ๋ชฉํ ์ข ๋ฃ ํ ํต๊ณ ์ฒ๋ฆฌ ๋ฐ ์ ์ ์ ์ฅ
๋ชฉํ ๋ง๊ฐ์ผ ์ดํ, UserAchivService.insertOrUpdateUserAchiv(goal)
์ ํธ์ถํ์ฌ ๋ฌ์ฑ๋ฅ ๊ณ์ฐ ๋ฐ ์ ์ฅ ์ํ.
๋ชฉํ ๊ธฐ๊ฐ ๋์ ๋์ ๋ GoalStatus
๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฑ๊ณต๋ฅ (completionRate
) ์ฐ์ถ.
@Transactional
public void insertOrUpdateUserAchiv(Goal goal) {
LocalDate start = goal.getStartDate();
LocalDate end = goal.getDueDate();
long totalDays = ChronoUnit.DAYS.between(start, end) + 1;
int countTrue = goalSatusService.countStatusDay(goal, start, end);
double userAchivCalc = totalDays > 0 ? countTrue / (double) totalDays : 0;
UserAchiv existing = userAchivRepository.findByGoalId(goal.getId());
if (existing != null) {
existing.setCompletionRate(userAchivCalc);
userAchivRepository.save(existing);
} else {
UserAchiv newAchiv = new UserAchiv();
newAchiv.setGoal(goal);
newAchiv.setCompletionRate(userAchivCalc);
userAchivRepository.save(newAchiv);
}
}
์ด ๊ฒฐ๊ณผ๋ UserAchiv
์ ๊ธฐ๋ก๋๋ฉฐ, ์ ์ ๋ณ ํต๊ณ๋ฅผ ์ ์ฅํ๋ ๊ธฐ๋ฐ ๋ฐ์ดํฐ๋ก ์ฌ์ฉ๋จ.
๊ตํ์ผ๊ธฐ ์์ฑ ์์ ๋ก์ง ๊ตฌํ
๊ทธ๋ฃน ํด ์์ ํ๋ฆ ์ ์ด
group.getCurrentTurn()
๊ณผ ๊ทธ๋ฃน์ ์ ์ ๋ฆฌ์คํธ ํฌ๊ธฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ํ ํ(Circular Queue) ๋ฐฉ์์ผ๋ก ํด์ ์ํ ์ฒ๋ฆฌ.group.getLastTurnDate()
๋ฅผ ํ์ธํ๊ณ , ๋น์ผ์ด ์ ๋ ์ด๋ฉด
group.setLastTurnDate(today)
๋ก ๋ ์ง๋ฅผ ๊ฐฑ์ ํ๊ณ ,(currentTurn + 1) % users.size()
๊ณ์ฐ์ ํตํด ๋ค์ ์ ์ ์๊ฒ ํด์ ๋ถ์ฌ.์ ์ ์ธ์ฆ ๊ธฐ๋ฐ ์ฐจ๋ก ํ์ธ ๋ฐ ์ ๊ทผ ์ ์ด
Principal
์์ ํ์ฌ ๋ก๊ทธ์ธ๋ ์ฌ์ฉ์์ ์ด๋ฉ์ผ์ ๊ฐ์ ธ์ ์ฌ์ฉ์ ์ ๋ณด(User
)๋ฅผ ์กฐํํจ.
ํ์ฌ ํด์ ํด๋นํ๋ ์ ์ (group.getUsers().get(currentTurn)
)์ ๋ก๊ทธ์ธ ์ฌ์ฉ์์ ID๋ฅผ ๋น๊ตํ์ฌ, ๋ณธ์ธ์ ์ฐจ๋ก์ผ ๋๋ง ์ผ๊ธฐ ์์ฑ ํ์ด์ง ์ ๊ทผ ํ์ฉ.
์ฐจ๋ก๊ฐ ์๋ ๊ฒฝ์ฐ์๋ ๋ฆฌ๋ค์ด๋ ํธ ์ฒ๋ฆฌ์ ํจ๊ป "์ง๊ธ์ ์ฐจ๋ก๊ฐ ์๋๋๋ค."
๋ฉ์์ง ์ ๋ฌ.
โ ์ด๋ Access Control(์ ๊ทผ ์ ์ด) ๊ตฌํ์ ํด๋นํ๋ฉฐ, ์ฌ์ฉ์ ํผ๋ ๋ฐฉ์ง์ UX ์ธก๋ฉด์์๋ ์ค์ํจ.
์์์ผ๊ณผ ๊ทธ๋ฃน ์ธ์ ์ ๊ธฐ๋ฐ ๋ ์ง ๋ฆฌ์คํธ ์์ฑ
List<LocalDate>
๋ฅผ ๊ตฌ์ฑ.๋ชฉํ ๋ฌ์ฑ ์ํ ๋งคํ ๋ฐ ๊ตฌ์กฐํ
GoalStatus
๋ฐ์ดํฐ๋ฅผ ๋ ์ง๋ณ๋ก ์กฐํ.{๋ชฉํ ID: {๋ ์ง ๋ฌธ์์ด: ์ฑ๊ณต ์ฌ๋ถ(Boolean)}}
ํํ์ **2์ค ๋งต(Map)**์ ๊ตฌ์ฑํ์ฌ, ๋ทฐ(View)์์ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ๋ก ๋ ๋๋ง ๊ฐ๋ฅํ๊ฒ ํจ.๋ฐ์ดํฐ ์ผ๊ด์ฑ๊ณผ ๋๊ธฐํ ์ ์ง
currentTurn
๋ฐ lastTurnDate
๋ฅผ ์ฆ์ ์
๋ฐ์ดํธํ์ฌ ๋ฐ์ดํฐ ๋ถ์ผ์น ๋ฐฉ์ง.currentTurn = 0
์ผ๋ก ๋กค๋ฐฑ ์ฒ๋ฆฌ ํ DB ์ ์ฅ ์ํ, ์ํ ๊ตฌ์กฐ ์ ์ง.GPT ๊ธฐ๋ฐ ์ด๋ชจ์ง ๊ฐ์ ์์ฝ ๊ธฐ๋ฅ
1. ์ฌ์ฉ์ ์ ๋ ฅ ์์ง ๋ฐ ํ๋กฌํํธ ์์ฑ
userMessage
)์ ์์งํจ."์ด ์ผ๊ธฐ๋ฅผ ์ด๋ชจ์ง 5๊ฐ๋ง ์ฌ์ฉํด์ ์์ฝํด์ค"
2. GPT API ์์ฒญ ๊ตฌ์ฑ
RestTemplate
์ ํ์ฉํ์ฌ POST ๋ฐฉ์์ผ๋ก OpenAI ์๋ฒ์ ์์ฒญ"model": "gpt-3.5-turbo"
"messages"
: ์ญํ (role)๊ณผ ๋ด์ฉ(content)์ผ๋ก ๊ตฌ์ฑ๋ ๋ฐฐ์ด"Authorization"
์ Bearer
ํ์์ API Key ์ฝ์
.properties
์์ @Value
์ด๋
ธํ
์ด์
์ผ๋ก ์ฃผ์
๋ฐ์ ๋ณด์์ ๋ถ๋ฆฌObjectMapper
๋ก ์ญ์ง๋ ฌํchoices[0].message.content
"๐ ์์ฝ ์คํจ"
๋ผ๋ fallback ๊ฐ์ ๋ฆฌํดํ๋๋ก ์์ธ ์ฒ๋ฆฌ ์ ์ฉ4. ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ก ๊ฒฐ๊ณผ ์ ๋ฌ