feat: AgendaSection todos JSON 파싱 로직 추가

- ObjectMapper를 사용하여 todos JSON 문자열을 파싱
- TodoJson DTO 클래스 추가
- parseTodosJson() 메서드 구현
- MeetingStatisticsResponse에서 실제 Todo 개수 계산
- 에러 처리 로직 추가 (파싱 실패 시 빈 리스트 반환)

JSON 구조: [{title, assignee, dueDate, description, priority}]

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Minseo-Jo
2025-10-29 15:26:15 +09:00
parent 093b8751d5
commit 77ad99bdc7
2 changed files with 56 additions and 5 deletions
@@ -1,5 +1,7 @@
package com.unicorn.hgzero.meeting.infra.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.unicorn.hgzero.common.dto.ApiResponse;
import com.unicorn.hgzero.meeting.biz.domain.AgendaSection;
import com.unicorn.hgzero.meeting.biz.domain.Meeting;
@@ -19,6 +21,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -36,6 +39,7 @@ public class MeetingAiController {
private final MinutesService minutesService;
private final AgendaSectionService agendaSectionService;
private final MeetingService meetingService;
private final ObjectMapper objectMapper;
@GetMapping("/{meetingId}/ai/participant-minutes")
@Operation(
@@ -162,8 +166,10 @@ public class MeetingAiController {
}
private AgendaSectionResponse.AgendaSectionItem convertToAgendaSectionItem(AgendaSection section) {
// todos와 pendingItems는 JSON 문자열이므로 파싱 필요 (현재는 null로 처리)
List<AgendaSectionResponse.AgendaSectionItem.TodoItem> todos = null;
// todos JSON 파싱
List<AgendaSectionResponse.AgendaSectionItem.TodoItem> todos = parseTodosJson(section.getTodos());
// pendingItems는 사용하지 않으므로 null 처리
List<String> pendingItems = null;
return AgendaSectionResponse.AgendaSectionItem.builder()
@@ -180,12 +186,57 @@ public class MeetingAiController {
.build();
}
/**
* todos JSON 문자열을 파싱하여 TodoItem 리스트로 변환
* JSON 구조: [{"title": "...", "assignee": "...", "dueDate": "...", "description": "...", "priority": "..."}]
*/
private List<AgendaSectionResponse.AgendaSectionItem.TodoItem> parseTodosJson(String todosJson) {
if (todosJson == null || todosJson.trim().isEmpty()) {
return new ArrayList<>();
}
try {
List<TodoJson> todoJsonList = objectMapper.readValue(
todosJson,
new TypeReference<List<TodoJson>>() {}
);
return todoJsonList.stream()
.map(json -> AgendaSectionResponse.AgendaSectionItem.TodoItem.builder()
.title(json.getTitle())
.assignee(json.getAssignee())
.dueDate(json.getDueDate())
.description(json.getDescription())
.priority(json.getPriority())
.build())
.collect(Collectors.toList());
} catch (Exception e) {
log.error("Failed to parse todos JSON: {}", todosJson, e);
return new ArrayList<>();
}
}
/**
* JSON 파싱을 위한 임시 DTO
*/
@lombok.Data
private static class TodoJson {
private String title;
private String assignee;
private String dueDate;
private String description;
private String priority;
}
private MeetingStatisticsResponse buildMeetingStatistics(String meetingId) {
Meeting meeting = meetingService.getMeeting(meetingId);
List<AgendaSection> sections = agendaSectionService.getAgendaSectionsByMeetingId(meetingId);
// AI가 추출한 Todo 수 계산 (todos는 JSON 문자열이므로 현재는 0으로 처리)
int todoCount = 0;
// AI가 추출한 Todo 수 계산
int todoCount = sections.stream()
.mapToInt(s -> parseTodosJson(s.getTodos()).size())
.sum();
// 회의 시간 계산
Integer durationMinutes = null;