Skip to content

[VISION] 반려동물 이미지 분석/보고서/추천 플로우 개선 및 폰트 적용#40

Merged
usn757 merged 1 commit intoPETTY-HUB:mainfrom
23MinL:feat/vision-config
May 25, 2025
Merged

[VISION] 반려동물 이미지 분석/보고서/추천 플로우 개선 및 폰트 적용#40
usn757 merged 1 commit intoPETTY-HUB:mainfrom
23MinL:feat/vision-config

Conversation

@23MinL
Copy link
Contributor

@23MinL 23MinL commented May 25, 2025

📜 PR 내용 요약

반려동물 이미지 분석 및 보고서·추천 플로우 개선,
카드 영역에 HakgyoansimDunggeunmisoTTF-B 웹폰트 적용
(프론트 디자인 일관성 및 UX 개선)
image
image
image


⚒️ 작업 및 변경 내용(상세하게)

1. PromptFactory.java

  • Gemini, Together API용 프롬프트 생성 메서드 구조화 및 세분화
  • 보호자에게 친화적인 분석 보고서 생성 템플릿(detailedPrompt) 개선
    (종, 품종, 외형, 무게, 맹수 여부, 감정·행동 등 주요 항목 포함)

2. VisionController.java

  • 이미지 업로드 시 파일 유효성 검사 강화
  • 업로드 시 임시 이미지 바이트 및 Base64 변환 값 세션에 저장 (플로우 연계성 강화)
  • 중간 분석 결과(임시 메시지) 및 최종 분석 결과 세션 저장 방식 정비
  • 에러 발생 시 상세 메시지 및 로그 추가, 사용자 예외 응답 강화

3. UnifiedFlowController.java

  • 반려동물 분석~추천 전체 플로우 세션 및 Flash Attribute 연계 일원화
  • 중간 분석 로딩, 최종 Vision 보고서, 추천 결과 페이지 모두 세션 방식으로 수정
    (이전 단계 데이터 재사용 및 예외 발생 시 graceful fallback 처리)
  • 업로드 이미지 Base64 인코딩 및 세션 저장
  • 추천 결과 표시 후 세션 데이터 정리

4. visionUpload.html

  • HakgyoansimDunggeunmisoTTF-B 웹폰트(눈누 CDN) 적용
    (카드 영역 전체에 font-family 선언)
  • 입력 폼, 버튼, 안내 문구 등 시각적 레이아웃 개선
  • UI 일관성 및 접근성(가독성) 개선

📚 기타 참고 사항

  • 리뷰 포인트:

    • 플로우 전환 간 세션 데이터가 정상적으로 유지되는지
    • 폰트 적용이 실제 브라우저에서 의도대로 반영되는지(크롬, 엣지 등 확인)
    • 업로드·분석·추천 기능 전체 예외처리와 사용자 피드백 정상 동작 여부
  • 빌드/배포:

    • 별도 빌드 이슈 없음
    • 정적 파일(CSS/폰트)은 별도 서버 경로 설정 필요 없음

@coderabbitai
Copy link

coderabbitai bot commented May 25, 2025

Summary by CodeRabbit

  • 신규 기능
    • 시각 분석 업로드 페이지 UI가 전면 리뉴얼되어, 이미지 미리보기, 오프라인 감지, 단계별 결과 표시, 향상된 오류 메시지, 성공 시 자동 리디렉션 등 사용자 경험이 크게 개선되었습니다.
  • 버그 수정
    • 세션을 활용한 데이터 관리로 분석 및 추천 과정에서 발생하던 오류와 예외 상황에 대한 처리가 강화되었습니다.
  • 스타일
    • Bootstrap 및 커스텀 스타일 적용으로 전체 레이아웃과 폼, 버튼, 알림, 로딩 애니메이션 등 시각적 요소가 개선되었습니다.
  • 문서화
    • HTML 템플릿에 Thymeleaf 레이아웃 및 프래그먼트 구조가 도입되어 유지보수성이 향상되었습니다.

Walkthrough

세션 기반 데이터 흐름과 예외 처리가 대폭 개선되었습니다. 주요 컨트롤러에서 플래시 속성 대신 세션을 일관적으로 사용하도록 변경되었으며, 이미지와 분석 결과, 추천 결과 등이 세션에 저장됩니다. 템플릿과 자바스크립트도 사용자 경험과 에러 처리를 강화하는 방향으로 리팩터링되었습니다.

Changes

파일/경로 요약 변경 내용 요약
.../UnifiedFlowController.java 세션 관리 및 데이터 흐름을 개선. 플래시 속성 제거, 세션에 분석 결과·이미지·이름·추천 결과 저장. 예외 및 리다이렉트 처리 강화. 메서드 시그니처 일부 변경. 로그 추가.
.../VisionController.java 세션 관리 추가. 이미지 및 분석 결과를 세션에 저장. 예외 처리 및 로깅 강화. VisionServiceImpl 의존성 추가. 메서드 시그니처에 HttpSession 파라미터 추가.
.../PromptFactory.java 프롬프트 마지막 문구를 사용자 친화적으로 요약하도록 수정. 로직 변경 없음.
.../visionUpload.html 템플릿을 Thymeleaf 레이아웃으로 리팩터링. 부트스트랩 및 커스텀 스타일 추가. 이미지 미리보기, 오프라인 감지, 인증 fetch, 두 단계 비동기 분석, 에러 처리 등 자바스크립트 대폭 개선. UI/UX 강화.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser
    participant VisionController
    participant UnifiedFlowController
    participant Session

    User->>Browser: 이미지 및 이름 입력 후 업로드
    Browser->>VisionController: /vision/species (파일, 이름, 세션)
    VisionController->>Session: 이미지, 이름, Base64 저장
    VisionController->>Browser: 중간 결과 반환

    Browser->>VisionController: /vision/analyze (파일, 이름, 세션)
    VisionController->>Session: 분석 결과 저장
    VisionController->>Browser: 분석 완료 응답

    Browser->>UnifiedFlowController: /analyze/report (세션)
    UnifiedFlowController->>Session: 분석 결과, 이미지, 이름 조회
    UnifiedFlowController->>Browser: 리포트 페이지 렌더링

    User->>Browser: 추천 요청
    Browser->>UnifiedFlowController: /recommend (세션)
    UnifiedFlowController->>Session: 추천 결과 저장
    UnifiedFlowController->>Browser: 추천 결과 반환 및 세션 정리
Loading

Possibly related PRs

Poem

🐰
세션에 담긴 이름과 미소,
이미지도 Base64로 살포시 저장해요.
분석과 추천, 한 걸음씩
오류엔 리다이렉트, 로그도 남기죠.
새 옷 입은 업로드 페이지,
토끼도 춤추는 UX의 봄바람!

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@23MinL
Copy link
Contributor Author

23MinL commented May 25, 2025

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented May 25, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (1)
src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java (1)

27-28: VisionController와 동일한 아키텍처 문제가 있습니다.

이 컨트롤러도 추상화와 구현체를 동시에 의존하고 있습니다. VisionController에 대한 리뷰 코멘트와 동일한 리팩토링이 필요합니다.

🧹 Nitpick comments (9)
src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java (1)

183-186: 세션 정리가 불완전합니다.

추천 결과 표시 후 세션에서 recommendationResultvisionReport만 제거하고 있습니다. 메모리 효율성을 위해 petImageBase64petName도 함께 제거해야 합니다.

         // 사용 후 세션에서 제거 (선택 사항)
         session.removeAttribute("recommendationResult");
         session.removeAttribute("visionReport");
+        session.removeAttribute("petImageBase64");
+        session.removeAttribute("petName");
src/main/resources/templates/visionUpload.html (8)

6-9: CDN 리소스에 SRI 및 crossorigin 속성 추가 고려
Bootstrap CDN 사용 시 보안 강화를 위해 Subresource Integrity(integrity)와 crossorigin="anonymous" 속성 추가를 권장합니다.


65-111: 프리포맷 텍스트 및 폼 컨트롤 스타일 개선 제안

  • <pre> 요소에 최대 높이 및 스크롤 처리가 잘 되어 있습니다.
  • .btn-primary, .form-label, .form-control 등 폼 요소 스타일도 직관적입니다.
  • 다만, 버튼 포커스(focus) 상태에 대한 별도 스타일 추가나, 시각장애인을 위한 대비(contrast) 검사 등을 고려해 보세요.

140-160: 애니메이션 및 성공 메시지 스타일 권장사항
로딩 펄스와 키프레임은 적절하게 정의되었습니다.
.success-message 역시 잘 꾸며져 있지만, 브라우저 호환성 확보를 위해 벤더 프리픽스(-webkit-, -moz-)를 추가 검토해 보세요.


165-173: 오프라인 알림에 ARIA 속성 추가 제안
#offlineAlert는 사용자에게 중요한 상태 정보를 제공합니다. role="alert" 또는 aria-live="assertive"를 추가해 보세요.


243-266: 온라인 상태 감지 로직 보완 제안
navigator.onLine은 일부 브라우저에서 완전 신뢰하기 어려울 수 있습니다. 네트워크 요청 타임아웃 체크를 추가하는 방법을 검토해 보세요.


268-299: alert() 대신 인라인 피드백 UI 사용 고려
파일 타입/크기 검증 시 alert()를 호출하는 대신, 페이지 내 #errorMessage 영역을 재활용해 사용자 경험을 일관되게 유지하는 것이 좋습니다.


302-335: 토큰 갱신 시 동시성 처리 주의
여러 요청이 동시에 401을 받을 경우 중복 갱신 요청이 발생할 수 있습니다. 갱신 플래그를 설정하거나 큐(queue)로 관리하는 패턴을 도입하는 것을 권장합니다.


337-389: 첫 번째 분석 단계 상태 관리 개선 제안
폼 전체를 display: none 처리하기보다는, 제출 버튼 비활성화(disabled) 및 스피너 토글만으로도 충분한 피드백이 가능합니다. 불필요한 DOM 트리 탐색(parentElement.parentElement)을 줄이는 방법을 추천합니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd5ba84 and c516466.

📒 Files selected for processing (4)
  • src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java (4 hunks)
  • src/main/java/io/github/petty/vision/adapter/in/VisionController.java (3 hunks)
  • src/main/java/io/github/petty/vision/helper/PromptFactory.java (1 hunks)
  • src/main/resources/templates/visionUpload.html (1 hunks)
🔇 Additional comments (6)
src/main/java/io/github/petty/vision/helper/PromptFactory.java (1)

81-81: 프롬프트 개선이 적절합니다!

"사용자 친화적으로"라는 표현을 추가하여 생성되는 보고서가 보호자에게 더 친근하고 이해하기 쉬운 형태로 제공되도록 개선한 것이 좋습니다.

src/main/resources/templates/visionUpload.html (5)

2-4: 레이아웃 데코레이터 및 XML 네임스페이스 설정이 적절합니다.
Thymeleaf 레이아웃 데코레이터와 XML 네임스페이스 선언이 올바르게 적용되어 있습니다.


35-63: 카드·프리뷰·스피너·결과 컨테이너 스타일 적절
.card-body, #imagePreview img, .spinner-border, #spinnerContainer, #result 등 주요 컨테이너 스타일이 일관성 있게 정의되어 있습니다.


174-196: 반려동물 정보 입력 폼 마크업 적절
<label for>id가 정확히 매핑되어 있고, required 속성도 잘 설정되어 있습니다. UX/폼 유효성 검사 측면에서 이상 없습니다.


201-238: 로딩 스피너 및 결과 UI 구조 적합
스피너와 결과 표시 영역이 명확히 분리되어 있어 사용자 피드백 흐름이 잘 구현되었습니다.


391-426: 두 번째 분석 및 리다이렉션 처리 적절
세션 기반 흐름과 사용자 피드백이 잘 조합되어 있습니다. 예외 처리도 상세해 문제 없습니다.

Comment on lines 23 to +24
private final VisionUseCase vision;
private final VisionServiceImpl visionService;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

아키텍처 문제: 추상화와 구현체를 동시에 의존하고 있습니다.

컨트롤러가 VisionUseCase(추상화)와 VisionServiceImpl(구현체)를 모두 의존하는 것은 의존성 역전 원칙(DIP)을 위반합니다. 이는 결합도를 높이고 테스트를 어렵게 만듭니다.

VisionUseCase 인터페이스에 필요한 모든 메서드를 정의하고, 컨트롤러는 인터페이스만 의존하도록 리팩토링하는 것을 권장합니다.

🤖 Prompt for AI Agents
In src/main/java/io/github/petty/vision/adapter/in/VisionController.java at
lines 23-24, the controller depends on both the abstraction VisionUseCase and
the concrete implementation VisionServiceImpl, violating the dependency
inversion principle. Remove the dependency on VisionServiceImpl and ensure the
controller only depends on the VisionUseCase interface. Refactor the code to use
VisionUseCase exclusively for all required methods, improving modularity and
testability.

Comment on lines +45 to +58
// UnifiedFlowController와 호환되도록 세션에 데이터 저장
session.setAttribute("petName", petName);

// 파일을 임시로 저장 (나중에 analyze에서 사용)
try {
byte[] imageBytes = file.getBytes();
session.setAttribute("tempImageBytes", imageBytes);

// 이미지를 Base64로 인코딩하여 세션에 저장
String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
} catch (IOException e) {
log.warn("이미지 저장 실패", e);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

메모리 사용량 최적화가 필요합니다.

현재 구현은 동일한 이미지를 두 가지 형태(원본 바이트와 Base64 문자열)로 세션에 저장하고 있어 메모리를 비효율적으로 사용합니다. 대용량 이미지의 경우 세션 메모리 부족 문제가 발생할 수 있습니다.

다음 중 하나의 방법을 고려해보세요:

  1. Base64 인코딩된 데이터만 저장하고 필요시 디코딩
  2. 파일 시스템이나 캐시 서버에 임시 저장 후 참조 ID만 세션에 저장
  3. 이미지 크기 제한 설정
-        // 파일을 임시로 저장 (나중에 analyze에서 사용)
-        try {
-            byte[] imageBytes = file.getBytes();
-            session.setAttribute("tempImageBytes", imageBytes);
-
-            // 이미지를 Base64로 인코딩하여 세션에 저장
-            String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
-            session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
-        } catch (IOException e) {
-            log.warn("이미지 저장 실패", e);
-        }
+        // 이미지를 Base64로 인코딩하여 세션에 저장 (메모리 효율성을 위해 한 번만 저장)
+        try {
+            byte[] imageBytes = file.getBytes();
+            String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
+            session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
+        } catch (IOException e) {
+            log.warn("이미지 저장 실패", e);
+            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "이미지 처리 중 오류가 발생했습니다.");
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// UnifiedFlowController와 호환되도록 세션에 데이터 저장
session.setAttribute("petName", petName);
// 파일을 임시로 저장 (나중에 analyze에서 사용)
try {
byte[] imageBytes = file.getBytes();
session.setAttribute("tempImageBytes", imageBytes);
// 이미지를 Base64로 인코딩하여 세션에 저장
String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
} catch (IOException e) {
log.warn("이미지 저장 실패", e);
}
// UnifiedFlowController와 호환되도록 세션에 데이터 저장
session.setAttribute("petName", petName);
// 이미지를 Base64로 인코딩하여 세션에 저장 (메모리 효율성을 위해 한 번만 저장)
try {
byte[] imageBytes = file.getBytes();
String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
} catch (IOException e) {
log.warn("이미지 저장 실패", e);
throw new ResponseStatusException(
HttpStatus.INTERNAL_SERVER_ERROR,
"이미지 처리 중 오류가 발생했습니다."
);
}
🤖 Prompt for AI Agents
In src/main/java/io/github/petty/vision/adapter/in/VisionController.java around
lines 45 to 58, the code stores the same image in the session both as raw bytes
and as a Base64 string, causing inefficient memory use. To fix this, choose one
approach: either store only the Base64-encoded string in the session and decode
it when needed, or save the image temporarily on the file system or a cache
server and store only a reference ID in the session. Additionally, consider
implementing an image size limit to prevent excessive memory consumption.

Comment on lines +59 to +65
try {
byte[] imageBytes = file.getBytes();
String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
} catch (Exception e) {
log.warn("이미지 저장 실패", e);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

이미지 인코딩 로직이 중복되어 있습니다.

VisionController의 /species 엔드포인트에서 이미 이미지를 Base64로 인코딩하여 세션에 저장하고 있습니다. 여기서 다시 동일한 작업을 수행하는 것은 불필요한 중복입니다.

이미 세션에 저장된 이미지를 재사용하거나, 공통 유틸리티 메서드로 추출하는 것을 권장합니다.

-            // 이미지를 Base64로 인코딩하여 세션에 저장
-            try {
-                byte[] imageBytes = file.getBytes();
-                String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
-                session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
-            } catch (Exception e) {
-                log.warn("이미지 저장 실패", e);
-            }
+            // VisionController에서 이미 저장한 이미지가 없는 경우에만 저장
+            if (session.getAttribute("petImageBase64") == null) {
+                try {
+                    byte[] imageBytes = file.getBytes();
+                    String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
+                    session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
+                } catch (Exception e) {
+                    log.error("이미지 저장 실패", e);
+                    throw new RuntimeException("이미지 처리 중 오류가 발생했습니다.", e);
+                }
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
byte[] imageBytes = file.getBytes();
String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
} catch (Exception e) {
log.warn("이미지 저장 실패", e);
}
// VisionController에서 이미 저장한 이미지가 없는 경우에만 저장
if (session.getAttribute("petImageBase64") == null) {
try {
byte[] imageBytes = file.getBytes();
String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
} catch (Exception e) {
log.error("이미지 저장 실패", e);
throw new RuntimeException("이미지 처리 중 오류가 발생했습니다.", e);
}
}
🤖 Prompt for AI Agents
In src/main/java/io/github/petty/pipeline/controller/UnifiedFlowController.java
around lines 59 to 65, the image Base64 encoding logic is duplicated from
VisionController's /species endpoint. To fix this, remove the redundant encoding
here and instead reuse the Base64 image string already stored in the session.
Alternatively, extract the encoding logic into a shared utility method and call
that method from both controllers to avoid duplication.

Comment on lines +113 to +138
/* 중간 보고서 스타일 개선 */
#interim {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 1.5rem;
border-radius: var(--border-radius-lg, 12px);
margin-bottom: 1rem;
text-align: center;
font-weight: 500;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
transition: all 0.3s ease;
}

#interim.hidden {
opacity: 0;
transform: translateY(-20px);
pointer-events: none;
}

#analyzingMessage {
font-style: italic;
color: var(--secondary-text-color, #6c757d);
text-align: center;
margin: 1rem 0;
font-size: 0.9rem;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

ARIA 라이브 리전 도입으로 접근성 강화
중간 보고서(#interim)와 분석 메시지(#analyzingMessage)는 동적으로 업데이트되므로, 스크린 리더가 즉시 읽도록 aria-live="polite"role="status" 속성 추가를 권장합니다.

🤖 Prompt for AI Agents
In src/main/resources/templates/visionUpload.html around lines 113 to 138, the
#interim and #analyzingMessage elements are dynamically updated but lack ARIA
live region attributes. To improve accessibility, add aria-live="polite" or
role="status" attributes to these elements so screen readers announce updates
immediately.

Comment on lines +11 to +33
<style>
/* 전체 폰트 설정 */
* {
font-family: 'HakgyoansimDunggeunmisoTTF-B', BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

/* body 배경색을 두 번째 이미지와 동일하게 설정 */
body {
background-color: var(--background-color, #f8f9fa);
}

/* 페이지 전용 스타일 */
.vision-container {
max-width: 600px;
margin: 0 auto;
}

.card {
margin-top: 2rem;
border-radius: var(--border-radius-lg, 12px);
box-shadow: var(--box-shadow-light, 0 4px 6px rgba(0, 0, 0, 0.1));
border: none;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

웹 폰트 로딩 누락 및 스타일 분리 제안
전역 폰트를 지정하셨으나, 실제로 @font-face 또는 CDN <link>를 통해 폰트 파일을 임포트하는 부분이 없습니다. 이대로면 기본 시스템 폰트로 대체될 수 있습니다.
또한, 전역 스타일과 레이아웃 전용 스타일을 별도의 CSS 파일로 분리하면 유지보수가 용이해집니다.

🤖 Prompt for AI Agents
In src/main/resources/templates/visionUpload.html around lines 11 to 33, the
global font-family is set but the custom font 'HakgyoansimDunggeunmisoTTF-B' is
not imported via @font-face or a CDN link, causing fallback to system fonts. Fix
this by adding an appropriate @font-face rule or a CDN link to load the font
file before using it. Additionally, move the global and layout-specific styles
into separate CSS files to improve maintainability and link them properly in the
HTML.

@usn757
Copy link
Contributor

usn757 commented May 25, 2025

PR 잘 검토했습니다. 반려동물 이미지 분석부터 보고서 생성, 추천까지 이어지는 전체 플로우의 일관성을 높이고 사용자 경험을 개선하시려는 고민과 노력이 코드 전반에서 느껴집니다. 주요 변경 사항들과 긍정적인 효과들을 아래와 같이 정리해 보았습니다.

✨ 핵심 플로우 통합 및 데이터 관리 효율성 증대:

  • UnifiedFlowController를 중심으로 분석-보고서-추천 플로우의 세션 및 Flash Attribute 연계를 일원화하여, 데이터 흐름의 명확성과 안정성을 크게 향상시켰습니다. 단계별 데이터가 세션 기반으로 일관되게 관리되면서 데이터 누락이나 불일치 문제도 효과적으로 줄어들 것으로 기대됩니다.
  • VisionController에서 이미지 업로드 시 파일 유효성 검사를 강화하고, 이미지 바이트 및 Base64 변환 값, 분석 결과 등을 세션에 체계적으로 저장하도록 정비하여 플로우 간 데이터 연동성을 높인 점이 돋보입니다.
  • PromptFactory에서 Gemini 및 Together API용 프롬프트 생성 로직을 구조화하고, 특히 보호자가 이해하기 쉬운 사용자 친화적 문장으로 detailedPrompt를 개선하여 LLM 응답의 질과 사용자 만족도를 높이는 데 기여할 것으로 보입니다.

🎨 사용자 경험(UX) 및 인터페이스 정교화:

  • visionUpload.html에 HakgyoansimDunggeunmisoTTF-B 웹폰트를 적용하고, 카드 영역을 포함한 입력 폼, 버튼, 안내 문구 등의 시각적 레이아웃을 개선하여 UI의 일관성과 가독성을 한층 끌어올렸습니다.
  • 오류 발생 시 상세 로그 기록과 함께 사용자 예외 응답을 강화하여, 문제 발생 시 디버깅 용이성을 높이고 사용자에게 보다 친절한 안내를 제공할 수 있게 된 점도 매우 긍정적입니다.
  • 추천 결과 표시 후 세션 데이터를 정리하는 등 메모리 관리 측면까지 세심하게 고려한 점이 좋습니다.

이렇게 많은 개선과 더불어, (몇몇 코드 분석 도구나 일반적인 권장 사항들도 참고하여) 앞으로 우리 시스템을 더욱 견고하고 발전시켜 나갈 몇 가지 주요 지점들을 함께 논의해보면 좋을 것 같습니다:

  • 백엔드 아키텍처 강화: VisionController 등에서 ServiceImpl 직접 의존 대신 인터페이스 기반(DIP) 설계를 적용하여 향후 변경에 대한 유연성을 높이고 테스트 용이성을 확보하면 좋겠습니다. 또한, 이미지 인코딩처럼 여러 곳에서 나타나는 중복 로직을 정리하여 전체적인 유지보수성을 개선할 수 있습니다.
  • 세션 데이터 관리 안정화: 대용량 이미지 처리 시 세션 메모리 부담을 줄일 수 있는 방안(예: Base64 단일 저장, 외부 저장소 활용 검토 등)을 고민하고, 특히 동일 사용자의 동시 요청으로 인해 발생할 수 있는 데이터 덮어쓰기 문제를 방지하여 안정성을 높일 필요가 있어 보입니다.
  • 프론트엔드 완성도 향상: 웹폰트가 다양한 브라우저와 환경에서 일관되게 로드되고 표시되는지(@font-face 설정, FOUT/FOIT 방지책 등 점검 및 실제 테스트) 확인이 필요합니다. 또한, ARIA 속성 활용이나 시맨틱 마크업 사용 같은 기본적인 웹 접근성 표준을 준수하여 모든 사용자의 경험을 개선하는 방향을 고려하면 좋겠습니다.

이번 PR을 통해 시스템 전반의 완성도와 사용자 경험이 크게 향상된 것 같습니다. 중요한 개선 작업 진행하시느라 정말 수고 많으셨습니다!

@usn757 usn757 merged commit cdf06aa into PETTY-HUB:main May 25, 2025
2 checks passed
@Juyoung8563
Copy link
Contributor

리뷰

  • 너무 예쁘게 잘 만들어 주셔서 감사합니다!
  • 중간 로딩 문구를 메인 디자인과 차별화 된 디자인으로 AI의 답변임을 강조하신 점 인상 깊었습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants