Skip to content

[FEATURE] 링크 검사 분석 요청 및 polling 연동#44

Merged
kbh0218 merged 4 commits into
devfrom
feat/#43-analysis-polling
May 21, 2026
Merged

[FEATURE] 링크 검사 분석 요청 및 polling 연동#44
kbh0218 merged 4 commits into
devfrom
feat/#43-analysis-polling

Conversation

@kbh0218

@kbh0218 kbh0218 commented May 20, 2026

Copy link
Copy Markdown
Contributor

Closes #43

개요

링크 검사 중 화면에서 기존 mock 타이머 기반 이동 흐름을 실제 백엔드 분석 API 연동 흐름으로 교체했습니다.

기존에는 scanning.tsx에서 일정 시간이 지나면 mock 결과 화면으로 이동했지만, 이번 작업에서는 POST /api/v1/analyses로 분석을 요청하고, 응답으로 받은 analysisId를 기준으로 GET /api/v1/analyses/{analysisId}를 polling하여 실제 분석 상태를 확인하도록 구현했습니다.

분석이 완료되면 백엔드 응답의 verdict 값에 따라 안전, 주의, 위험 결과 화면으로 이동합니다. 결과 화면으로는 AnalysisResponse 전체 객체를 넘기지 않고 analysisId, url, verdict만 전달하며, 각 결과 화면에서 analysisId를 기준으로 분석 결과를 다시 조회해 화면 표시용 AnalysisResponse를 확보하도록 구성했습니다.

이 구조를 통해 route params를 작고 안정적으로 유지하면서도, 결과 화면 직접 진입이나 앱 상태 유실 상황에서도 analysisId만 있으면 분석 결과를 다시 확보할 수 있도록 했습니다.

주요 구현 내용

  • POST /api/v1/analyses 분석 요청 API 연동
  • Clerk getToken() 기반 보호 API 호출 구조 적용
  • GET /api/v1/analyses/{analysisId} polling 구현
  • polling 간격 2초 적용
  • 최대 polling 대기 시간 30초 적용
  • queued 상태에서는 polling 유지
  • failed 상태 또는 API 에러 발생 시 사용자 안내 메시지 표시
  • succeeded 상태에서 verdict 값에 따라 결과 화면 분기
  • safe 결과는 scan-result 화면으로 이동
  • caution 결과는 scan-result-caution 화면으로 이동
  • danger 결과는 scan-result-block 화면으로 이동
  • 컴포넌트 unmount 시 polling timer/request 정리
  • 결과 화면 이동 시 AnalysisResponse 전체 객체 대신 analysisId, url, verdict만 전달
  • 결과 화면 공통 분석 결과 조회 hook 추가
  • 결과 화면 3개에서 analysisId 기준 AnalysisResponse 조회
  • 분석 결과 조회 중/실패 상태에 대한 UI 메시지 표시
  • summary -> reasons -> mock reason 순서로 판정 이유 표시
  • analysis?.originalUrl ?? url ?? '' 기준으로 표시 URL 정리
  • analysis?.finalUrl을 즉시 URL 접속 및 mock 저장 데이터에 반영
  • safe/caution mock 저장 흐름에서 실제 analysisId를 우선 사용
  • POST /saved-links 실제 저장 API 연동은 다음 작업으로 분리

파일별 역할

  • api/analyses.ts: 분석 요청/조회 API 타입 및 호출 함수 추가
  • app/(tabs)/(home)/scanning.tsx: 분석 요청, polling, 상태별 에러 처리, 결과 화면 분기 처리
  • hooks/use-analysis-result.ts: 결과 화면에서 analysisId 기준으로 분석 결과를 조회하는 공통 hook 추가
  • utils/analysis-result-display.ts: route param, 표시 URL, 최종 URL, 판정 이유, 사이트명 표시 유틸 추가
  • app/(tabs)/(home)/scan-result.tsx: 안전 결과 화면에서 analysisId 수신 및 분석 결과 조회 반영
  • app/(tabs)/(home)/scan-result-caution.tsx: 주의 결과 화면에서 analysisId 수신 및 분석 결과 조회 반영
  • app/(tabs)/(home)/scan-result-block.tsx: 위험 결과 화면에서 analysisId 수신 및 분석 결과 조회 반영

해결한 이슈 목록

  • scanning.tsx의 mock 타이머 기반 결과 이동 흐름을 실제 분석 API 흐름으로 교체
  • 분석 요청 시 Clerk 인증 토큰 기반 보호 API 호출 적용
  • 분석 요청 성공 후 analysisId 기준 polling 수행
  • polling 중 queued 상태 처리
  • 분석 성공 시 verdict에 따라 안전/주의/위험 결과 화면으로 이동
  • 분석 실패 또는 API 에러 발생 시 사용자 안내 표시
  • unmount 시 timer/request 정리
  • 결과 화면으로 analysisId, url, verdict 전달
  • AnalysisResponse 전체 객체를 route params로 전달하지 않도록 처리
  • 결과 화면 3개에서 analysisId route param 수신
  • 결과 화면 3개에서 fetchAnalysis() 기반 분석 결과 조회
  • 결과 화면에서 조회 실패 시에도 기본 UI가 깨지지 않도록 fallback 처리
  • 백엔드 summary 또는 reasons 기반 판정 이유 표시
  • safe/caution mock 저장 데이터에 실제 analysisId 우선 반영
  • 저장 API 연동은 이번 PR 범위에서 제외

체크 사항

  • 커밋/코딩 컨벤션에 맞게 작성
  • 프론트 API 클라이언트 사용 규칙 준수
  • 결과 화면/hook에서 직접 fetch()를 호출하지 않음
  • 결과 화면/hook에서 직접 API base URL을 만들지 않음
  • 결과 화면/hook에서 직접 Authorization 헤더를 붙이지 않음
  • 결과 화면/hook에서 { data: ... } 응답을 직접 unwrap하지 않음
  • 보호 API는 authenticatedApiRequest() 기반 fetchAnalysis()를 통해 호출
  • /auth/me를 수동 선호출하는 흐름을 만들지 않음
  • AnalysisResponse 전체 객체를 JSON.stringify해서 route params로 넘기지 않음
  • POST /api/v1/saved-links 저장 API 연동은 이번 작업에 포함하지 않음

검증

  • Swagger 기준 GET /api/v1/analyses/{analysisId} 응답이 ApiResponseAnalysisResponse -> AnalysisResponse 구조임을 확인
  • FastAPI 분석 엔진 health 응답 확인

참고

이번 PR에서는 분석 결과 화면의 저장 버튼이 아직 실제 POST /api/v1/saved-links를 호출하지 않습니다.

safe/caution 결과 화면의 저장 흐름은 기존 mock addLink 기반으로 유지하되, 이후 저장 API 연동 작업에서 바로 사용할 수 있도록 실제 analysisId를 우선 반영하도록 정리했습니다.

결과 화면은 앱 내부 이동 직후에도 analysisId 기준으로 분석 결과를 조회합니다. 따라서 polling 중 이미 받은 AnalysisResponse를 route params로 직접 전달하지 않고, 결과 화면에서 필요한 시점에 다시 조회하는 구조입니다.

Screenshots or Video

  • 요청 후 검사 결과가 DB에 잘 들어온 것을 확인할 수 있습니다.
image
  • 앱에서는 받은 정보 그대로 "현재 기준으로 안전한 링크로 판단됩니다."를 띄웁니다.
image
  • 연결 오류 등 문제가 있을때 뜨는 화면입니다.
image
  • 최대 대기시간인 30초를 지나면 뜨는 화면입니다.
image

@kbh0218 kbh0218 requested review from minsoo0506 and sunm2n May 20, 2026 09:39
@kbh0218 kbh0218 self-assigned this May 20, 2026
@kbh0218 kbh0218 added the feature 기능개발 label May 20, 2026
const reason = getMockScanResultReason('safe');
const analysisId = getRouteParam(analysisIdParam);
const url = getRouteParam(urlParam);
const { analysis, isLoading, errorMessage } = useAnalysisResult(analysisId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

결과 화면에서 다시 받아온 analysis.verdict가 현재 화면 종류와 다른 경우가 처리되지 않는 것 같습니다. 예를 들어 /scan-result 화면으로 직접 들어왔는데, analysisId로 다시 조회한 결과가 danger라면 화면은 여전히 “안전한 웹사이트입니다.”로 보일 수 있습니다.

analysis.verdict를 확인해서 현재 화면과 다르면 맞는 결과 화면으로 이동시키거나, 결과 화면을 verdict 기준으로 공통 렌더링하면 더 안전할 것 같습니다.

일반적인 검사 흐름에서는 scanning.tsx에서 verdict에 맞는 결과 화면으로 보내기 때문에 문제가 잘 생기지는 않을 것 같습니다만... PR 설명처럼 결과 화면 직접 진입이나 앱 상태 유실 상황까지 고려한다면, 결과 화면에서 analysisId로 조회한 analysis.verdict가 현재 화면과 맞는지 한 번 확인해도 좋을 것 같습니다.

@kbh0218 kbh0218 May 20, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

맞습니다. 일반 검사 흐름에서는 scanning 화면에서 verdict별 결과 화면으로 이동해서 문제가 잘 드러나지 않지만, 결과 화면 직접 진입이나 앱 상태 유실 상황에서는 route와 재조회된 analysis.verdict가 어긋날 수 있다고 판단했습니다.

그래서 각 결과 화면에서 analysisId가 있으면 verdict가 확인되기 전까지 판정 UI를 보여주지 않고 로딩 상태만 표시하도록 했고, 조회된 verdict가 현재 화면 타입과 다르면 해당 verdict에 맞는 결과 화면으로 replace하도록 보완했습니다. 이 방식으로 “안전 화면이 잠깐 보였다가 위험 화면으로 이동”하는 깜빡임도 막았습니다!

const reason = getAnalysisReasonText(analysis, getMockScanResultReason('safe'));
const [saveModalVisible, setSaveModalVisible] = useState(false);

const handleSave = (title: string) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

analysisId만 가지고 결과 화면에 직접 들어온 경우, 분석 결과를 불러오기 전에도 저장 버튼을 누를 수 있습니다. 이때 아직 URL 정보가 없어서 빈 URL이 저장될 수 있을 것 같습니다.

분석 결과 로딩 중이거나 표시할 URL이 없을 때는 저장 버튼을 비활성화하거나, handleSave에서 displayUrl이 없으면 저장하지 않도록 막으면 좋을 것 같습니다...!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

맞습니다. analysisId 직접 진입이나 조회 실패 케이스에서 displayUrl이 비어 있는 상태로 저장될 여지가 있어 보였습니다.

저장 버튼은 로딩 중이거나 표시할 URL이 없으면 비활성화하도록 수정했고, 혹시 모달 상태 경계에서 저장 핸들러가 호출되더라도 canSave가 false면 저장하지 않도록 가드도 추가했습니다. 같은 저장 흐름을 쓰는 주의 결과 화면에도 동일하게 반영했습니다!

@minsoo0506 minsoo0506 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.

넵 수정 확인했습니다:)

@kbh0218 kbh0218 merged commit 4c1eb7e into dev May 21, 2026
@kbh0218 kbh0218 deleted the feat/#43-analysis-polling branch May 21, 2026 02:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature 기능개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] 링크 검사 분석 요청 및 polling 연동

2 participants