Skip to content

[Fix] SOLUTION 기능 지원 누락 수정 및 AI 라우터와 전처리 코드 수정#203

Merged
gaeunee2 merged 2 commits intodevfrom
fix/202-solution-feature-support
Feb 19, 2026
Merged

[Fix] SOLUTION 기능 지원 누락 수정 및 AI 라우터와 전처리 코드 수정#203
gaeunee2 merged 2 commits intodevfrom
fix/202-solution-feature-support

Conversation

@gaeunee2
Copy link
Copy Markdown
Collaborator

@gaeunee2 gaeunee2 commented Feb 19, 2026

📌 관련 이슈

🏷️ PR 타입

  • ✨ 기능 추가 (Feature)
  • 🐛 버그 수정 (Bug Fix)
  • ♻️ 리팩토링 (Refactoring)
  • 📝 문서 수정 (Documentation)
  • 🎨 스타일 변경 (Style)
  • ✅ 테스트 추가 (Test)

📝 작업 내용

  • "SOLUTION" 기능을 Spring의 SUPPORTED_FEATURES에 추가하여 400 에러 수정
  • AI 라우터에서 "SOLUTION" → "solution"으로 자동 변환 처리
  • AI preprocessing 코드에서 PDF 파일 경로 문제 및 이미지 전처리 인자 오류 수정

📸 스크린샷

✅ 체크리스트

  • 코드 리뷰를 받을 준비가 완료되었습니다
  • 테스트를 작성하고 모두 통과했습니다
  • 문서를 업데이트했습니다 (필요한 경우)
  • 코드 스타일 가이드를 준수했습니다
  • 셀프 리뷰를 완료했습니다

📎 기타 참고사항

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 채팅 서비스에서 더 많은 기능 유형을 지원하도록 확장했습니다. Solution, Variation, Graph, CreateGraph 등 추가 기능 옵션을 이제 인식하고 처리할 수 있습니다.

@gaeunee2 gaeunee2 requested a review from chowon442 February 19, 2026 13:57
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

ChatServiceImpl의 SUPPORTED_FEATURES 컬렉션에 "Solution", "SOLUTION", "VARIATION", "GRAPH", "CreateGraph"를 추가하여 기능 검증 범위를 확대했습니다. DB 툴코드(대문자)와 AI 기능명(PascalCase) 모두 지원하도록 개선했습니다.

Changes

Cohort / File(s) Summary
기능 검증 범위 확대
src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java
SUPPORTED_FEATURES에 대문자 DB toolCode("SOLUTION", "VARIATION", "GRAPH")와 PascalCase AI feature names("Solution", "CreateGraph")를 추가하여 기능 문자열 검증 범위 확대

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 기능 목록에 새로운 친구들을 추가했네,
SOLUTION과 GRAPH가 이제 반갑게 인사하고,
대문자부터 PascalCase까지 모두 환영해,
400 에러는 이제 안녕, 정상 처리 만세! 🎉
작은 변화가 큰 기쁨을 만든다.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive PR에서 제시된 변경사항 중 코드 관련 요구사항을 검토했을 때, SUPPORTED_FEATURES에 SOLUTION 추가 사항은 구현되었으나, AI 라우터 변환 처리와 AI preprocessing 수정 사항에 대한 구체적인 코드 변경 내용이 제시된 raw_summary에서 명확하지 않습니다. PR에서 언급한 AI 라우터의 대소문자 변환 처리와 AI preprocessing의 PDF/이미지 처리 수정 사항에 대한 구체적인 코드 변경 내용을 확인하여 이슈 요구사항 충족 여부를 검증하세요.
Out of Scope Changes check ❓ Inconclusive 제공된 raw_summary는 ChatServiceImpl.java의 SUPPORTED_FEATURES 확장만 보여주며, 다른 변경사항들(AI 라우터, preprocessing 수정)에 대한 상세 정보가 불완전합니다. AI 라우터와 AI preprocessing 코드의 전체 변경사항을 검토하여 이슈 범위 내의 변경인지 확인하세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 주요 변경사항인 'SOLUTION 기능 지원 누락 수정'을 명확히 포함하고 있으며, AI 라우터와 전처리 코드 수정도 함께 언급하고 있습니다.
Description check ✅ Passed PR 설명은 템플릿을 대부분 따르고 있으며, 관련 이슈, PR 타입, 작업 내용, 체크리스트 항목들을 포함하고 있습니다. 다만 스크린샷 섹션이 비어있고 모든 체크리스트 항목이 완료되지 않았습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/202-solution-feature-support

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@gaeunee2 gaeunee2 self-assigned this Feb 19, 2026
@gaeunee2 gaeunee2 added the bug Something isn't working label Feb 19, 2026
Copy link
Copy Markdown
Member

@chowon442 chowon442 left a comment

Choose a reason for hiding this comment

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

좋아요! 👍

@gaeunee2 gaeunee2 merged commit 9683226 into dev Feb 19, 2026
1 of 2 checks passed
Copy link
Copy Markdown

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java (1)

288-303: ⚠️ Potential issue | 🟠 Major

대문자 기능명("SOLUTION" 등)으로 크레딧이 잘못된 금액 차감됨

validateFeatures를 통과한 대문자 feature명("SOLUTION" 등)이 CreditUseService.useCredit()featureName으로 전달됩니다. FEATURE_BASE_COST 맵에는 PascalCase 키만 있으므로("Solution" 등), 정확한 문자열 매칭에 실패합니다. 예외를 발생시키지 않고 기본 비용 5를 반환하여 예상 비용보다 훨씬 적은 크레딧이 차감됩니다("SOLUTION"의 경우 20이 아닌 5로 차감). 줄 297에서 응답을 검증하지 않아 이 오류가 감지되지 않습니다.

validateFeatures에서 feature명을 정규화(대문자 → PascalCase)하거나, CreditUseService에서 대소문자 무시 매칭을 지원하도록 보완이 필요합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java`
around lines 288 - 303, The chosen-features loop passes raw feature strings
(e.g., "SOLUTION") to CreditUseService.useCredit causing FEATURE_BASE_COST
(which uses PascalCase keys like "Solution") to miss and fall back to default
cost; normalize feature names to PascalCase before creating CreditUseRequest (or
alternatively make CreditUseService do case-insensitive lookup against
FEATURE_BASE_COST) so the featureName sent to useCredit matches the map
keys—update the code path that builds CreditUseRequest in ChatServiceImpl (or
the validateFeatures normalization step) to convert incoming feature tokens to
PascalCase prior to calling creditUseService.useCredit.
🧹 Nitpick comments (1)
src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java (1)

532-539: validateFeatures의 대소문자 구분 허용 방식 — 유지보수 취약성

새 기능이 추가될 때마다 AI 기능명(PascalCase)과 DB toolCode(대문자) 두 가지 변형을 SUPPORTED_FEATURES에 수동으로 등록해야 하는 구조는 누락 위험이 높습니다 (이번 "VARIANT" 누락이 그 예입니다). TreeSet(String.CASE_INSENSITIVE_ORDER)를 사용하면 각 기능명을 한 번만 등록하고 대소문자를 무시한 룩업이 가능합니다.

♻️ 리팩터링 제안
-    // 지원되는 기능 목록 - DB toolCode(대문자)와 AI feature명(PascalCase) 모두 허용
-    private static final Set<String> SUPPORTED_FEATURES = Set.of(
-            "Solve", "Check", "Explain", "Variant", "Practice",
-            "Solution", "SOLUTION",
-            "VARIATION",
-            "GRAPH", "CreateGraph"
-    );
+    // 지원되는 기능 목록 (대소문자 무시 매칭)
+    private static final Set<String> SUPPORTED_FEATURES;
+    static {
+        Set<String> s = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+        s.addAll(List.of("Solve", "Check", "Explain", "Variant", "Practice",
+                         "Solution", "Graph", "CreateGraph"));
+        SUPPORTED_FEATURES = Collections.unmodifiableSet(s);
+    }

validateFeatures는 변경 없이 SUPPORTED_FEATURES.contains(feature)를 그대로 사용할 수 있으며, TreeSet(String.CASE_INSENSITIVE_ORDER) 덕분에 "SOLUTION", "solution", "Solution" 모두 허용됩니다.

주의: 이 접근 방식을 채택하면 현재 AI 라우터에서 수행하는 명시적 대소문자 정규화에 의존하는 다운스트림 코드가 여전히 올바르게 작동하는지 확인해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java`
around lines 532 - 539, The current validateFeatures method relies on
SUPPORTED_FEATURES.contains(feature) but SUPPORTED_FEATURES is case-sensitive,
forcing duplicate entries for different capitalizations; change the
SUPPORTED_FEATURES collection initialization to a case-insensitive set (e.g.,
new TreeSet<>(String.CASE_INSENSITIVE_ORDER) or equivalent) so validateFeatures
can remain unchanged and lookups accept "SOLUTION"/"solution"/"Solution"; after
changing SUPPORTED_FEATURES, run a quick check of downstream code that assumes
explicit normalization (AI router or any code that expected specific casing) to
ensure behavior remains correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java`:
- Around line 70-76: SUPPORTED_FEATURES contains uppercase variants ("SOLUTION",
"VARIATION", "GRAPH") and "Practice", but FEATURE_BASE_COST lookups are
case-sensitive so CreditUseService.useCredit() can charge the default 5 instead
of the intended value; fix by normalizing feature names before cost lookup
(e.g., map incoming feature via a canonicalizer like feature =
normalizeFeature(feature) or feature =
StringUtils.capitalize(feature.toLowerCase())/toLowerCase()) or make
FEATURE_BASE_COST case-insensitive by populating both variants (add entries for
"SOLUTION", "VARIATION", "GRAPH" and "Practice") and ensure ToolDataInitializer
and any registration logic use the same canonical form so
CreditUseService.useCredit() and FEATURE_BASE_COST use the same symbol set.

---

Outside diff comments:
In `@src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java`:
- Around line 288-303: The chosen-features loop passes raw feature strings
(e.g., "SOLUTION") to CreditUseService.useCredit causing FEATURE_BASE_COST
(which uses PascalCase keys like "Solution") to miss and fall back to default
cost; normalize feature names to PascalCase before creating CreditUseRequest (or
alternatively make CreditUseService do case-insensitive lookup against
FEATURE_BASE_COST) so the featureName sent to useCredit matches the map
keys—update the code path that builds CreditUseRequest in ChatServiceImpl (or
the validateFeatures normalization step) to convert incoming feature tokens to
PascalCase prior to calling creditUseService.useCredit.

---

Nitpick comments:
In `@src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java`:
- Around line 532-539: The current validateFeatures method relies on
SUPPORTED_FEATURES.contains(feature) but SUPPORTED_FEATURES is case-sensitive,
forcing duplicate entries for different capitalizations; change the
SUPPORTED_FEATURES collection initialization to a case-insensitive set (e.g.,
new TreeSet<>(String.CASE_INSENSITIVE_ORDER) or equivalent) so validateFeatures
can remain unchanged and lookups accept "SOLUTION"/"solution"/"Solution"; after
changing SUPPORTED_FEATURES, run a quick check of downstream code that assumes
explicit normalization (AI router or any code that expected specific casing) to
ensure behavior remains correct.

Comment on lines +70 to 76
// 지원되는 기능 목록 - DB toolCode(대문자)와 AI feature명(PascalCase) 모두 허용
private static final Set<String> SUPPORTED_FEATURES = Set.of(
"Solve", "Check", "Explain", "Variant", "Practice"
"Solve", "Check", "Explain", "Variant", "Practice",
"Solution", "SOLUTION",
"VARIATION",
"GRAPH", "CreateGraph"
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for VARIATION, VARIANT patterns and related feature code
rg -n --type=java 'VARIATION|VARIANT' -B2 -A2

Repository: Team-Proovy/Proovy-server

Length of output: 1794


🏁 Script executed:

# Look at the ChatServiceImpl file around the SUPPORTED_FEATURES
sed -n '65,85p' src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java

Repository: Team-Proovy/Proovy-server

Length of output: 915


🏁 Script executed:

# Check how validateFeatures and credit deduction use SUPPORTED_FEATURES
rg -n --type=java 'validateFeatures|SUPPORTED_FEATURES' src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java -B1 -A3

Repository: Team-Proovy/Proovy-server

Length of output: 876


🏁 Script executed:

# Search for toolCode references in entity definitions or migrations
find . -type f \( -name "*.java" -o -name "*.sql" \) | xargs rg -l 'toolCode|TOOL_CODE' 2>/dev/null | head -20

Repository: Team-Proovy/Proovy-server

Length of output: 901


🏁 Script executed:

# Check Tool entity definition
cat src/main/java/com/proovy/global/tool/entity/Tool.java

Repository: Team-Proovy/Proovy-server

Length of output: 1775


🏁 Script executed:

# Check the full ToolDataInitializer to see all tool initializations
cat src/main/java/com/proovy/global/tool/config/ToolDataInitializer.java

Repository: Team-Proovy/Proovy-server

Length of output: 2117


🏁 Script executed:

# Search for all toolCode initializations to see the complete list
rg -n 'toolCode\(' src/main/java/com/proovy/global/tool/config/ToolDataInitializer.java -B1 -A1

Repository: Team-Proovy/Proovy-server

Length of output: 457


🏁 Script executed:

# Check if there are migrations that define toolCode values
find . -type f -name "*.sql" | xargs rg 'SOLVE|CHECK|EXPLAIN|VARIANT|PRACTICE|SOLUTION|GRAPH' 2>/dev/null | head -30

Repository: Team-Proovy/Proovy-server

Length of output: 51


🏁 Script executed:

# Check how features are used in credit deduction and feature validation
sed -n '280,310p' src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java

Repository: Team-Proovy/Proovy-server

Length of output: 1836


🏁 Script executed:

# Search for where feature names map to tools/toolCodes
rg -n 'featureName|chosenFeatures' src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java -B2 -A2

Repository: Team-Proovy/Proovy-server

Length of output: 673


🏁 Script executed:

# Check if there's any normalization or conversion between feature names and toolCodes
rg -n 'toLowerCase|toUpperCase|normalize' src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java

Repository: Team-Proovy/Proovy-server

Length of output: 51


🏁 Script executed:

# Look for the AI router or feature name conversion logic
rg -n 'Solve|Check|Explain|Variant|Practice' src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java

Repository: Team-Proovy/Proovy-server

Length of output: 135


🏁 Script executed:

# Search for AI feature mapping or conversion logic
rg -n '"Solve"|"Check"|"Explain"|"Variant"|"Practice"' --type=java -B2 -A2

Repository: Team-Proovy/Proovy-server

Length of output: 4339


🏁 Script executed:

# Check if there are any tests or documentation about supported features
find . -type f \( -name "*Test.java" -o -name "*.md" \) | xargs rg -l 'SUPPORTED_FEATURES|feature' 2>/dev/null | head -10

Repository: Team-Proovy/Proovy-server

Length of output: 51


🏁 Script executed:

# Look at the complete MessageTool entity to understand tool usage
cat src/main/java/com/proovy/domain/conversation/entity/MessageTool.java

Repository: Team-Proovy/Proovy-server

Length of output: 832


🏁 Script executed:

# Check if there are any other places where features are validated or mapped
rg -n 'validateFeatures|chosenFeatures' --type=java -B3 -A3

Repository: Team-Proovy/Proovy-server

Length of output: 4366


🏁 Script executed:

# Check CreditUseService to see how it looks up feature cost
sed -n '25,50p' src/main/java/com/proovy/domain/credit/service/CreditUseService.java

Repository: Team-Proovy/Proovy-server

Length of output: 770


🏁 Script executed:

# Search for where the feature name gets passed to credit service and how it's handled
rg -n 'getFeatureCost|FEATURE_BASE_COST' src/main/java/com/proovy/domain/credit/service/CreditUseService.java -B2 -A5

Repository: Team-Proovy/Proovy-server

Length of output: 1241


🏁 Script executed:

# Check if there's any normalization when passing feature to credit service
sed -n '285,310p' src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java

Repository: Team-Proovy/Proovy-server

Length of output: 1508


🏁 Script executed:

# Look at how "Practice" feature is handled (it's in SUPPORTED_FEATURES but not in some mappings)
rg -n 'Practice' --type=java

Repository: Team-Proovy/Proovy-server

Length of output: 209


대문자 기능명의 크레딧 차감 비용 매핑 누락

현재 코드는 "SOLUTION", "VARIATION", "GRAPH" 같은 대문자 기능명을 SUPPORTED_FEATURES에 추가했으나, 이들 기능이 실제로 크레딧 차감 시 비용 매핑에서 빠져 있습니다.

문제 상황:

  1. 대문자 기능명 비용 매핑 누락

    • 클라이언트가 "SOLUTION" 전송 → 검증 통과 ✓
    • 크레딧 차감 시 CreditUseService.useCredit() 호출 (line 293)
    • FEATURE_BASE_COST 맵에는 "Solution"만 있고 "SOLUTION"은 없음
    • getOrDefault() 호출로 기본값 5 크레딧으로 처리 (line 161, silent fallback)
    • 실제 비용("Solution": 20 크레딧)과 다른 금액 차감
  2. "Practice" 기능의 비용 매핑 누락

    • SUPPORTED_FEATURES"Practice"가 있음 (line 72)
    • FEATURE_BASE_COST에는 없음 (line 28-34)
    • "Practice" 기능 사용 시 기본값 5 크레딧으로 차감
  3. DB 도구 불일치

    • ToolDataInitializer는 3개 도구만 생성: GRAPH, SOLUTION, VARIATION
    • "Solve", "Check", "Explain", "Variant", "Practice"는 DB 도구 등록 없음

수정 방법:

대문자 기능명이 Spring 검증 단계에서 도착하면, 크레딧 차감 전에 정규화된 형태로 변환하거나, FEATURE_BASE_COST에 모든 기능명 변형(대문자 포함)을 추가하세요.

private static final Map<String, Integer> FEATURE_BASE_COST = Map.of(
        "Solve", 10,
        "Explain", 5,
        "CreateGraph", 5,
        "Variant", 5,
        "Solution", 20,
        "Check", 3,
+       "SOLUTION", 20,
+       "VARIATION", 5,
+       "GRAPH", 5,
+       "Practice", 5  // 누락된 기능
);

또는 검증 후 정규화: feature.toLowerCase() 또는 case-insensitive 비용 조회 로직 추가.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/proovy/domain/conversation/service/ChatServiceImpl.java`
around lines 70 - 76, SUPPORTED_FEATURES contains uppercase variants
("SOLUTION", "VARIATION", "GRAPH") and "Practice", but FEATURE_BASE_COST lookups
are case-sensitive so CreditUseService.useCredit() can charge the default 5
instead of the intended value; fix by normalizing feature names before cost
lookup (e.g., map incoming feature via a canonicalizer like feature =
normalizeFeature(feature) or feature =
StringUtils.capitalize(feature.toLowerCase())/toLowerCase()) or make
FEATURE_BASE_COST case-insensitive by populating both variants (add entries for
"SOLUTION", "VARIATION", "GRAPH" and "Practice") and ensure ToolDataInitializer
and any registration logic use the same canonical form so
CreditUseService.useCredit() and FEATURE_BASE_COST use the same symbol set.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fix] SOLUTION 기능 지원 누락으로 인한 400 에러 수정

2 participants