Skip to content

Feat/sw 70 - AI 북마크 분석 로직 고도화 및 API 에러 처리 표준화#44

Merged
jin2304 merged 7 commits into
devfrom
feat/SW-70
May 9, 2026
Merged

Feat/sw 70 - AI 북마크 분석 로직 고도화 및 API 에러 처리 표준화#44
jin2304 merged 7 commits into
devfrom
feat/SW-70

Conversation

@jin2304

@jin2304 jin2304 commented May 4, 2026

Copy link
Copy Markdown
Member

💡 이슈

resolve {#43}

🤩 개요

  • AI 북마크 분석의 정확도를 높이기 위한 Identity-First 분류 전략을 도입하고, 프론트엔드와 백엔드 간의 API 에러 핸들링 체계를 표준화하여 서비스의 기술적 완성도와 안정성을 강화했습니다.

🧑‍💻 작업 사항

  • AI 분석 엔진 정교화
    • Identity-First 전략(사이트 유형 우선 분류)이 반영된 프롬프트 v4 적용
    • AI 추천 태그와 기존 태그 간의 대소문자 무시 매칭 및 명칭 유지 로직 구현
    • '미분류' 폴더 추천 시 태그 기반으로 폴더명을 자동 교정하는 안정 장치 추가
  • 데이터 컨텍스트 확장
    • 폴더별 상위 사용 태그(Top Tags) 빈도수 데이터를 AI 문맥에 포함하여 추천 정확도 향상
  • 프론트엔드 통신 및 UI 안정화
    • ApiError 클래스 도입으로 백엔드 비즈니스 에러 코드와 사용자 메시지 연동 표준화
    • 분석 재실행 시 이전 추천 태그가 중복으로 쌓이던 UI 상태 관리 버그 수정
  • 코드 및 리소스 최적화
    • 미사용 로직(콘텐츠 유형 추출 등) 제거 및 프롬프트 파일 확장자 정리(.md)

📖 참고 사항

  • application.properties에서 프롬프트 버전 및 리소스 경로 설정이 변경되었습니다.
  • 백엔드에서 내려주는 커스텀 에러 메시지가 프론트엔드 알림창(alert)에 직접 노출되도록 개선되어 사용자 피드백이 더욱 명확해졌습니다.

Summary by CodeRabbit

릴리스 노트

  • New Features

    • AI 링크 분석 기능 강화: 사용자 폴더 맥락을 활용하여 더 정확한 폴더 추천 및 태그 제안 제공
    • 개선된 에러 메시지: API 오류 발생 시 더 명확하고 구체적인 오류 정보 표시
  • Bug Fixes

    • 태그 추적 로직 개선으로 AI 제안 태그 처리 안정화

jin2304 and others added 4 commits May 2, 2026 01:56
## 변경사항

### 1. 프롬프트 v4 (link-analysis-system-v4.md)
- Step 1 기준을 "도메인(Domain) 레벨 일치"로 명확화
- 기존: "85% 이상 일치" (모호함) → 개선: "도메인이 완벽하게 일치"
- 구체적 예제 추가 (Netflix vs 스포츠 폴더의 도메인 불일치)
- Netflix 같은 사례에서 표면 특성(스트리밍)이 아닌 핵심 도메인(OTT)으로 판단하도록 유도

### 2. 코드 개선 (LinkAnalysisServiceImpl.java)
- 새 메서드 추가: inferCategoryFromTitles(List<String> titles)
  * 샘플 제목들에서 자동으로 폴더의 주요 카테고리 추론
  * 키워드 기반 분류: OTT, AI도구, 개발, 디자인, 스포츠, 협업, 콘텐츠
  * 점수 기반 우선순위: 50% 이상 단일 카테고리, 그 외 혼합 (예: "AI도구 & OTT")

### 3. 폴더 컨텍스트 블록 개선
- 기존: "- AI (3개, 최근 2026-04-27) 최근 저장: [...]"
- 개선: "- AI (3개, 최근 2026-04-27, 주요 카테고리: AI도구 & OTT) 최근 저장: [...]"
- AI가 폴더의 의미적 성격을 명확히 인지 가능

## 효과
- Netflix → 스포츠(오류) 제거
- Netflix → OTT(정확) 추천
- 다른 서비스도 도메인 기반 정확 분류 기대

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Step 1을 더 엄격하게 ('애매하면 NO')
- Step 2 실행을 의무화 (Step 1 = NO일 때)
- suggestedTags에서 도메인 태그 추출 방법 구체화
- Netflix → 스포츠 오분류 제거 기대

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
LinkAnalysisServiceImpl: 추천 태그 매칭 로직 고도화 및 미분류 폴더 자동 보정 로직 구현.
FolderContext / BookmarkDao: AI 문맥 정보 강화를 위한 폴더별 상위 태그 빈도수 데이터 연동.
application.properties: 프롬프트 v4 설정 및 리소스 경로 다각화 반영.
prompts/*.md: Identity-First 전략 및 최신 서비스 예시가 반영된 기능성 프롬프트 리소스 구축.
LinkMetadataExtractor: 불필요한 콘텐츠 유형 추출 로직 제거 및 코드 최적화.
fetchClient.ts: ApiError 클래스 도입 및 표준 에러 메시지 추출 함수 구현을 통한 예외 처리 체계 구축.
QueryProvider.tsx: 전역 Mutation 에러 핸들링 고도화를 통해 사용자에게 의미 있는 에러 메시지 제공.
SaveLinkDialog.tsx: 재분석 시 AI 추천 태그 중복 축적 버그 해결 및 상태 초기화 로직 수정.
@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 54bb84f4-a196-4cbc-9274-c82b8fed0117

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

이 변경은 AI 기반 링크 분석 기능을 향상시킵니다. 프론트엔드에서는 API 오류 처리를 구조화하고, 백엔드에서는 사용자 폴더별 문맥을 조회하여 AI 프롬프트에 통합합니다. 새로운 FolderContext 도메인 객체와 MyBatis 쿼리를 추가하고, LinkAnalysisServiceImpl을 확장하여 폴더 문맥을 기반으로 프롬프트를 동적으로 구성합니다. 프롬프트 템플릿을 v3에서 v4로 업그레이드하고, 페이지 콘텐츠에서 contentType 필드를 제거합니다. 전반적으로 AI 분석의 정확성을 높이기 위해 폴더 문맥 정보를 활용하는 엔드투엔드 기능을 추가합니다.

Sequence Diagram

sequenceDiagram
    participant User as 사용자
    participant Frontend as Frontend<br/>(SaveLinkDialog)
    participant Service as LinkAnalysisServiceImpl
    participant DAO as BookmarkDao
    participant DB as Database
    participant Extractor as LinkMetadataExtractor
    participant AI as OpenAI API

    User->>Frontend: 링크 저장 및 AI 분석 요청
    Frontend->>Service: analyze(url, memberId, ...)
    
    Service->>Extractor: extract(url)
    Extractor-->>Service: PageContent<br/>(title, description,<br/>keywords, headings)
    
    Service->>DAO: selectFolderContexts<br/>(memberId, sampleLimit, tagLimit)
    DAO->>DB: SELECT folder contexts<br/>with aggregated stats
    DB-->>DAO: List<Map<String, Object>>
    DAO-->>Service: List<FolderContext>
    
    Service->>Service: buildPrompt<br/>(pageContent, folders,<br/>tags, folderContexts)
    
    Note over Service: folderContext 있으면<br/>enrichedUserPromptTemplate<br/>사용, 아니면<br/>basicUserPromptTemplate 사용
    
    Service->>AI: POST /chat/completions<br/>(enriched prompt)
    AI-->>Service: JSON response<br/>(title, description,<br/>suggestedTags, suggestedFolder)
    
    Service->>Service: parseAndEnrich<br/>(response)
    Note over Service: 태그 매칭, 폴더 재매핑,<br/>미분류 처리
    
    Service-->>Frontend: AI 분석 결과
    Frontend->>Frontend: aiSuggestedTags 업데이트<br/>(모든 AI 제안 태그 추적)
    Frontend-->>User: 분석 완료, 태그/폴더 제안
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 폴더 컨텍스트 담아
프롬프트 심어 AI 에게
더 똑똑한 분석이 자라나고
오류 처리도 단단해지니
링크 정리, 이제 더 정확하다네! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed PR 제목은 AI 북마크 분석 로직 고도화 및 API 에러 처리 표준화라는 두 가지 주요 변경사항을 명확하고 간결하게 요약하고 있으며, 실제 변경사항과 완전히 일치합니다.
Description check ✅ Passed PR 설명서가 저장소의 필수 템플릿 구조를 준수하고 있으며, 이슈 번호, 개요, 작업 사항, 참고 사항이 상세하게 작성되었습니다.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/SW-70

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 833500fab1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +193 to +194
// Track ALL AI-suggested tags (both existing and new) for cleanup on re-analysis
aiTagNames.add(tag.tagName);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve manually selected tags across re-analysis

aiSuggestedTags now records every AI-suggested tag, including tags the user had already selected manually before analysis. On the next analysis pass, baseTags removes all tags in prevAiTags, so any manual tag that happened to be suggested by AI gets dropped unexpectedly. This regression occurs when a user preselects a tag (e.g., an existing tag), runs AI analysis, then re-runs analysis; the preselected tag is treated as AI-owned and removed.

Useful? React with 👍 / 👎.

CASE WHEN mf.folder_type = 'UNORGANIZED' THEN 1 ELSE 0 END ASC,
stats.last_created_at DESC NULLS LAST,
mf.folder_name ASC
LIMIT 50

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid truncating folder candidates used for AI matching

This hard LIMIT 50 truncates the folder context set before prompt construction, and the enriched prompt path only sends {folderContext} (not a full folder-name fallback), so folders beyond the first 50 are invisible to the model. For users with more than 50 root folders, AI cannot recommend omitted existing folders and may instead suggest creating new duplicates.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/lib/api/fetchClient.ts (1)

144-150: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

2xx 성공 응답의 JSON.parse 호출이 try-catch로 보호되지 않음

비-2xx 경로(Lines 128–136)는 JSON.parse를 try-catch 내부에서 안전하게 처리하지만, 2xx 성공 경로의 Line 150 JSON.parse(text)는 예외 처리가 없습니다. 서버가 2xx 상태코드와 함께 HTML(예: 게이트웨이 오류 페이지)이나 plain text를 반환하면 SyntaxErrorApiError가 아닌 형태로 그대로 전파되어, QueryProvidererror instanceof ApiError 분기를 우회합니다.

🛡️ 제안 수정
-  const json: ApiResponse<T> = JSON.parse(text);
+  let json: ApiResponse<T>;
+  try {
+    json = JSON.parse(text);
+  } catch {
+    throw new ApiError({ message: DEFAULT_API_ERROR_MESSAGE });
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/lib/api/fetchClient.ts` around lines 144 - 150, The 2xx success
path in fetch response handling calls JSON.parse(text) without try-catch
(variable json: ApiResponse<T>), so wrap the parse in a try-catch around
JSON.parse(text) and, on any SyntaxError or parse failure, throw an ApiError (or
construct the same error shape used in the non-2xx branch) so callers (e.g.,
QueryProvider's error instanceof ApiError) handle it consistently; update the
parsing block that produces `json` to catch parse errors and rethrow a mapped
ApiError with useful context (status, body) rather than letting SyntaxError
escape.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/providers/QueryProvider.tsx`:
- Around line 30-32: The onError handler in QueryProvider.tsx calls
alert(getApiErrorMessage(error)) unconditionally, which blocks navigation when
fetchClient throws ApiError({ code: 'AUTH_EXPIRED' }); update the handler to
detect that error (check error.code === 'AUTH_EXPIRED' or error instanceof
ApiError with code) and skip showing the alert in that case so the existing
fetchClient redirect to '/login' is not blocked; for all other errors continue
to call getApiErrorMessage(error) and alert as before.

In `@src/main/java/com/web/SearchWeb/linkanalysis/domain/FolderContext.java`:
- Around line 113-126: In FolderContext where the Array-to-List conversion
happens (the block checking "if (value instanceof Array sqlArr)"), keep the
current behavior of swallowing SQLException but add a DEBUG-level log in the
catch to record the exception and context (include sqlArr and/or the column name
if available) so failures are visible during debugging; use the existing logger
(or add one if missing) and call logger.debug with a descriptive message and the
caught SQLException, then continue to return the empty/fallback result as
before.

---

Outside diff comments:
In `@frontend/src/lib/api/fetchClient.ts`:
- Around line 144-150: The 2xx success path in fetch response handling calls
JSON.parse(text) without try-catch (variable json: ApiResponse<T>), so wrap the
parse in a try-catch around JSON.parse(text) and, on any SyntaxError or parse
failure, throw an ApiError (or construct the same error shape used in the
non-2xx branch) so callers (e.g., QueryProvider's error instanceof ApiError)
handle it consistently; update the parsing block that produces `json` to catch
parse errors and rethrow a mapped ApiError with useful context (status, body)
rather than letting SyntaxError escape.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 53c55939-f420-448e-ac7b-13257445e364

📥 Commits

Reviewing files that changed from the base of the PR and between 6570a01 and 833500f.

📒 Files selected for processing (17)
  • frontend/src/components/dialogs/SaveLinkDialog.tsx
  • frontend/src/components/providers/QueryProvider.tsx
  • frontend/src/lib/api/fetchClient.ts
  • src/main/java/com/web/SearchWeb/bookmark/dao/BookmarkDao.java
  • src/main/java/com/web/SearchWeb/bookmark/dao/MybatisBookmarkDao.java
  • src/main/java/com/web/SearchWeb/linkanalysis/domain/FolderContext.java
  • src/main/java/com/web/SearchWeb/linkanalysis/domain/PageContent.java
  • src/main/java/com/web/SearchWeb/linkanalysis/service/LinkAnalysisServiceImpl.java
  • src/main/java/com/web/SearchWeb/linkanalysis/service/LinkMetadataExtractor.java
  • src/main/resources/application.properties
  • src/main/resources/mapper/bookmark-mapper.xml
  • src/main/resources/prompts/link-analysis-system-v1.md
  • src/main/resources/prompts/link-analysis-system-v2.md
  • src/main/resources/prompts/link-analysis-system-v3.md
  • src/main/resources/prompts/link-analysis-system-v4.md
  • src/main/resources/prompts/link-analysis-user-basic.md
  • src/main/resources/prompts/link-analysis-user-enriched.md
💤 Files with no reviewable changes (1)
  • src/main/java/com/web/SearchWeb/linkanalysis/domain/PageContent.java

Comment on lines 30 to +32

// 2. 사용자에게는 어떤 상황에서도 기술 정보 없이 일반적인 안내 문구만 제공
alert('요청 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.');
// 2. 백엔드가 내려준 사용자용 메시지가 있으면 그대로 안내한다.
alert(getApiErrorMessage(error));

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 | 🟡 Minor | ⚡ Quick win

AUTH_EXPIRED 에러 시 alert()/login 리다이렉트를 차단

fetchClient는 토큰 갱신 실패 시 window.location.href = '/login'을 설정한 직후 ApiError({ code: 'AUTH_EXPIRED' })를 throw합니다(fetchClient.ts Lines 108–115). React Query가 이를 onError로 전달하면 alert()가 실행되어 브라우저의 다이얼로그가 네비게이션을 블로킹합니다. 사용자는 알림을 직접 닫아야 로그인 페이지로 이동할 수 있습니다.

이 동작은 해당 throw 구문이 이번 PR에서 신규 추가(~)된 것이므로 새로 도입된 회귀입니다.

🛡️ 제안 수정 — AUTH_EXPIRED alert 생략
-              // 2. 백엔드가 내려준 사용자용 메시지가 있으면 그대로 안내한다.
-              alert(getApiErrorMessage(error));
+              // 2. AUTH_EXPIRED는 /login 리다이렉트 중이므로 alert 를 생략한다.
+              if (error instanceof ApiError && error.code === 'AUTH_EXPIRED') return;
+              alert(getApiErrorMessage(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
// 2. 사용자에게는 어떤 상황에서도 기술 정보 없이 일반적인 안내 문구만 제공
alert('요청 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.');
// 2. 백엔드가 내려준 사용자용 메시지가 있으면 그대로 안내한다.
alert(getApiErrorMessage(error));
// 2. AUTH_EXPIRED는 /login 리다이렉트 중이므로 alert 를 생략한다.
if (error instanceof ApiError && error.code === 'AUTH_EXPIRED') return;
alert(getApiErrorMessage(error));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/providers/QueryProvider.tsx` around lines 30 - 32,
The onError handler in QueryProvider.tsx calls alert(getApiErrorMessage(error))
unconditionally, which blocks navigation when fetchClient throws ApiError({
code: 'AUTH_EXPIRED' }); update the handler to detect that error (check
error.code === 'AUTH_EXPIRED' or error instanceof ApiError with code) and skip
showing the alert in that case so the existing fetchClient redirect to '/login'
is not blocked; for all other errors continue to call getApiErrorMessage(error)
and alert as before.

Comment on lines +113 to +126
if (value instanceof Array sqlArr) {
try {
Object inner = sqlArr.getArray();
if (inner instanceof Object[] objArr) {
List<String> out = new ArrayList<>(objArr.length);
for (Object o : objArr) {
if (o != null) out.add(o.toString());
}
return Collections.unmodifiableList(out);
}
} catch (SQLException ignored) {
// fall through to empty
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

SQLException 무시 처리는 적절하나 로깅 추가 권장

java.sql.Array 변환 시 SQLException을 무시하고 있습니다. Graceful degradation 관점에서는 적절하지만, 디버깅을 위해 DEBUG 레벨 로깅을 추가하면 좋겠습니다.

🔧 선택적 로깅 추가
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
 `@Getter`
 `@Builder`
 public class FolderContext {
     // ...
             } catch (SQLException ignored) {
-                // fall through to empty
+                log.debug("Failed to convert SQL Array to List<String>", ignored);
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/web/SearchWeb/linkanalysis/domain/FolderContext.java`
around lines 113 - 126, In FolderContext where the Array-to-List conversion
happens (the block checking "if (value instanceof Array sqlArr)"), keep the
current behavior of swallowing SQLException but add a DEBUG-level log in the
catch to record the exception and context (include sqlArr and/or the column name
if available) so failures are visible during debugging; use the existing logger
(or add one if missing) and call logger.debug with a descriptive message and the
caught SQLException, then continue to return the empty/fallback result as
before.

@jin2304 jin2304 changed the title Feat/sw 70 Feat/sw 70 - AI 북마크 분석 로직 고도화 및 API 에러 처리 표준화 May 6, 2026
@jin2304 jin2304 changed the title Feat/sw 70 - AI 북마크 분석 로직 고도화 및 API 에러 처리 표준화 Feat/sw 70 - AI 북마크 분석 로직 고도화 및 API 에러 처리 표준화 May 6, 2026
jin2304 added 3 commits May 7, 2026 21:23
SaveLinkDialog: AI 추천 태그 상태 무결성 확보: 사용자가 기존에 수동 선택한 태그를 AI 추천 태그 목록에 포함하지 않도록 baseTags 비교 조건 추가 및 재분석 시 수동 선택 태그가 정리 대상에 섞이는 현상 방지.

QueryProvider: 인증 만료 UX 개선: AUTH_EXPIRED 에러는 로그아웃 및 로그인 페이지 이동 흐름에서 이미 처리되므로 전역 alert 중복 노출을 차단하여 불필요한 경고 팝업 제거.
bookmark-mapper.xml: 폴더 추천 후보 확장: LLM 폴더 추천용 루트 폴더 컨텍스트 조회 제한을 50개에서 100개로 확대하여 폴더 수가 많은 사용자 환경에서 기존 폴더 인식 범위 개선.

LinkAnalysisServiceImpl: 프롬프트 컨텍스트 최적화: 전체 폴더명과 설명은 최대 100개까지 제공하되 태그 및 샘플 제목 상세 정보는 상위 30개 폴더로 제한하여 추천 후보 누락 방지와 프롬프트 과대화 완화.

LinkAnalysisServiceImpl: 폴더 설명 반영 강화: 폴더별 설명이 존재하는 경우 샘플 및 태그 상세 정보 여부와 무관하게 기본 컨텍스트에 포함하여 AI가 사용자의 폴더 의도를 더 안정적으로 판단하도록 개선.

FolderContext: SQL Array 변환 진단성 개선: SQLException 발생 시 예외를 완전히 무시하지 않고 debug 로그로 원인을 남겨 폴더 컨텍스트 누락 문제 추적 가능성 확보.
CustomOAuth2MemberService: 신규 회원 초기화 안정성 확보: OAuth2 로그인 사용자 정보 저장과 신규 가입자 미분류 폴더 보장 로직이 하나의 트랜잭션 경계 안에서 실행되도록 loadUser에 @transactional 추가.

CustomOAuth2MemberService: 가입 직후 폴더 조회 안정성 개선: 소셜 회원 생성 직후 기본 폴더 생성 과정에서 DB 동기화 타이밍이 어긋나는 상황을 줄여 첫 진입 시 폴더 목록 누락 가능성 완화.
@jin2304 jin2304 merged commit 705c0ae into dev May 9, 2026
2 checks passed
@jin2304 jin2304 self-assigned this May 25, 2026
@jin2304 jin2304 added 📝 docs 문서 작성 및 수정 ✨ feat 새로운 기능을 추가 ⚡️ improve 성능 개선 and removed ⚡️ improve 성능 개선 labels May 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📝 docs 문서 작성 및 수정 ✨ feat 새로운 기능을 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SW-69 AI 북마크 분석 로직 고도화 및 API 에러 처리 표준화] AI 북마크 분석 로직 고도화 및 API 에러 처리 표준화

1 participant