Skip to content

feat: 인스타그램 장소 추출 파이프라인 유기적 연동 및 응답 구조 재설계 - #40

Merged
minsour merged 7 commits into
mainfrom
feature/GM-88-instagram-scrap-e2e
Jul 26, 2026
Merged

minsour merged 7 commits into
mainfrom
feature/GM-88-instagram-scrap-e2e

Conversation

@minsour

@minsour minsour commented Jul 10, 2026 •

Copy link
Copy Markdown
Member

📌 Related Issue

GM-88

🚀 Description

  • Instagram URL → scrap→ AI extraction → geocoding 파이프라인을 하나의 유기적 흐름으로 연동하고, 응답 구조를 재설계했습니다.
    • 응답을 PlaceMatch[] (extracted + matches) 구조로 바꿨습니다.
    • 빈 응답의 경우 에러 -> 빈 배열 응답으로 수정했습니다.
  • API Swagger 문서를 추가했습니다.
  • e2e 테스트를 보완했습니다.
  • EXTRACTION_PROMPT 를 개선했습니다.
  • 전체 플로우가 연동되면서, 임시 확인용 _test/geocode 엔드포인트를 제거했습니다.

✅ Done

  • 응답을 PlaceMatch[](extracted/matches) 장소별 그룹 구조로 재설계
  • 에러 정책 정리: 부분 실패·결과 없음은 빈 matches(정상), 전부 실패만 GEOCODER_ALL_FAILED(502)
  • AI 추출 스키마(snake) → camel 도메인 타입(ExtractedPlace) 매핑
  • area_type 분류 기준 프롬프트 보강
  • 파이프라인 e2e 추가(외부 어댑터만 override, 조립 전체 관통 검증)
  • 임시 _test/geocode 엔드포인트 및 DTO 제거
  • place API Swagger 문서화(요청은 valibot에서 생성, 응답/에러 스키마)

📢 Notes

  • 실제 인스타 스크래핑은에 이슈가 있어 원인 파악중에 있으며, 별도 PR로 분리해서 작업할 예정입니다.

Summary by CodeRabbit

  • 새 기능
    • 장소 등록 API가 장소별 extracted 정보와 지오코딩 후보 matches를 함께 반환합니다.
    • 일부 장소의 지오코딩이 실패해도, 성공한 장소 결과는 응답에 포함됩니다(후보는 정렬됨).
  • 버그 수정
    • 모든 지오코딩이 실패한 경우 502 오류를 반환합니다.
    • 지오코딩 결과가 없는 경우 오류 대신 빈 matches로 처리합니다.
  • 문서
    • 장소 등록 API의 요청/응답/오류 Swagger 문서 스키마가 추가·정비되었습니다.
  • 기타
    • 테스트용 지오코딩 엔드포인트가 제거되었습니다.

minsour added 4 commits July 9, 2026 03:59
평평한 GeoCandidate[] 대신 추출 장소 단위 PlaceMatch[]로 반환한다.
서로 다른 장소의 후보가 섞이지 않도록 장소별로 랭킹하고, best/candidates와
AI가 뽑은 query(relation 포함)를 함께 담는다. 부분 실패·결과 없음은 빈
후보로 유지하고 전부 실패한 경우만 GEOCODER_ALL_FAILED로 취급한다.
area_type 분류 기준을 프롬프트에 명시해 지오코딩 정확도를 높인다.
외부 어댑터(스크래퍼/AI/지오코더)만 override로 대체하고 나머지 조립을
실제로 관통시켜 POST /places의 PlaceMatch[] 계약·에러 경로를 검증한다.
임시 지오코딩 확인용 엔드포인트와 관련 DTO(testGeocodeRequestSchema)를
제거하고, 컨트롤러의 GeocoderService 직접 의존도 정리한다.
POST /api/v1/place/places에 @ApiTags/@ApiOperation/@ApiBody/@apiresponse를
붙인다. 요청 스키마는 valibot(createPlaceRequestSchema)에서 생성하고, 응답·에러
스키마는 OpenAPI 스키마 상수로 문서화한다. @nestjs/swagger가 공개 export하지
않는 SchemaObject 타입은 common/swagger에 헬퍼로 둔다.
@minsour minsour self-assigned this Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 002832f9-a4dc-43ed-a7a2-786cfbaa186b

📥 Commits

Reviewing files that changed from the base of the PR and between 0578ade and fe4f2e3.

📒 Files selected for processing (1)
  • src/modules/place/place.controller.ts

📝 Walkthrough

Walkthrough

장소 추출 API가 장소별 extracted 정보와 matches 후보를 반환하도록 변경되었습니다. 지오코딩 부분 실패·전체 실패 처리가 조정되었고, Swagger 스키마와 단위/E2E 테스트가 새 응답 계약을 반영합니다.

Changes

장소 매칭 응답 흐름

Layer / File(s) Summary
응답 타입과 API 스키마
src/modules/place/place.type.ts, src/modules/place/place.dto.ts, src/common/swagger/schema.ts, src/modules/place/place.controller.ts
ExtractedPlace와 PlaceMatch 타입, 요청·응답·오류 JSON Schema, Swagger 메타데이터를 추가하고 임시 지오코딩 엔드포인트를 제거했습니다.
장소별 지오코딩 매칭 처리
src/modules/place/place.service.ts, src/modules/place/place.service.spec.ts
쿼리별 { extracted, matches } 결과를 구성하고, 부분 실패 시 빈 매치 배열을 유지하며 전체 실패 시 오류를 반환하도록 변경했습니다. 빈 추출 결과와 후보 정렬 검증도 갱신했습니다.
외부 의존성 mock 기반 E2E 검증
e2e/place.e2e.spec.ts
스크래퍼·AI·지오코더를 mock으로 교체하고 성공, 전체 지오코딩 실패, 잘못된 요청의 응답을 검증합니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PlaceController
  participant PlaceService
  participant ScraperService
  participant AiService
  participant GeocoderService
  Client->>PlaceController: POST /api/v1/place/places
  PlaceController->>PlaceService: extractFromUrl(url)
  PlaceService->>ScraperService: fetchPost(url)
  PlaceService->>AiService: extract(post)
  PlaceService->>GeocoderService: searchAll(query)
  GeocoderService-->>PlaceService: 후보 또는 실패
  PlaceService-->>PlaceController: PlaceMatch[]
  PlaceController-->>Client: 201 응답 또는 502 오류
Loading

Possibly related PRs

Suggested reviewers: labyrinth30, sudosubin, kkardy

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 인스타그램 장소 추출 파이프라인 통합과 응답 구조 재설계를 잘 요약합니다.
Description check ✅ Passed 템플릿의 필수 섹션을 모두 채웠고, 변경 내용과 완료 항목, 노트가 구체적으로 정리되어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/GM-88-instagram-scrap-e2e

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.

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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/modules/place/place.dto.ts`:
- Around line 19-77: 각 스키마에 실제 응답 타입과 일치하는 required 배열을 추가하세요. coordinateSchema,
geoCandidateSchema, extractedPlaceSchema, placeMatchSchema,
placeMatchListResponseApiSchema, errorResponseApiSchema의 필수 필드를 타입 정의에 맞춰 지정하고,
특히 geoCandidateSchema는 provider, providerPlaceId, placeName, address,
coordinate만 required로 설정하며 distance, mapUrl, phone, category는 제외하세요.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a8240820-44ad-4df8-97ac-ad5d95f296ff

📥 Commits

Reviewing files that changed from the base of the PR and between b655fbb and 0578ade.

📒 Files selected for processing (7)
  • e2e/place.e2e.spec.ts
  • src/common/swagger/schema.ts
  • src/modules/place/place.controller.ts
  • src/modules/place/place.dto.ts
  • src/modules/place/place.service.spec.ts
  • src/modules/place/place.service.ts
  • src/modules/place/place.type.ts

Comment on lines +19 to +77
const coordinateSchema: SchemaObject = {
type: "object",
properties: {
lat: { type: "number", example: 37.5445 },
lng: { type: "number", example: 127.0559 },
},
};

const geoCandidateSchema: SchemaObject = {
type: "object",
properties: {
provider: { type: "string", enum: ["kakao", "google"] },
providerPlaceId: { type: "string" },
placeName: { type: "string" },
address: { type: "string" },
coordinate: coordinateSchema,
distance: { type: "number", nullable: true },
mapUrl: { type: "string", nullable: true },
phone: { type: "string", nullable: true },
category: { type: "string", nullable: true },
},
};

const extractedPlaceSchema: SchemaObject = {
type: "object",
properties: {
placeName: { type: "string" },
areaName: { type: "string" },
areaType: { type: "string", enum: [...AREA_TYPES] },
relation: { type: "string" },
},
};

const placeMatchSchema: SchemaObject = {
type: "object",
properties: {
extracted: extractedPlaceSchema,
matches: {
type: "array",
items: geoCandidateSchema,
description: "지오코딩 결과 후보",
},
},
};

export const placeMatchListResponseApiSchema: SchemaObject = {
type: "object",
properties: {
data: { type: "array", items: placeMatchSchema },
},
};

// TODO: KakaoProvider 확인용 임시 의존성으로 전체 플로우 연동 후 제거합니다.
export type TestGeocodeRequest = v.InferOutput<typeof testGeocodeRequestSchema>;
export const errorResponseApiSchema: SchemaObject = {
type: "object",
properties: {
errorCode: { type: "string", example: "GEOCODER_ALL_FAILED" },
message: { type: "string", example: "장소 검색이 모두 실패했습니다." },
},
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# GeoCandidate 타입 정의에서 필수/선택 필드 확인
rg -n 'interface GeoCandidate' -A 20 src/infrastructures/geocoder/geocoder.type.ts

Repository: mash-up-kr/Team-MINO-Node

Length of output: 583


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== place.dto.ts ==" 
nl -ba src/modules/place/place.dto.ts | sed -n '1,180p'

echo
echo "== related place types ==" 
rg -n 'interface .*Place|type .*Place|interface .*Error|type .*Error|extractedPlace|placeMatch|errorResponse' -A 20 -B 5 src | sed -n '1,260p'

Repository: mash-up-kr/Team-MINO-Node

Length of output: 222


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== place.dto.ts =="
sed -n '1,180p' src/modules/place/place.dto.ts

echo
echo "== related place types =="
rg -n 'interface .*Place|type .*Place|interface .*Error|type .*Error|extractedPlace|placeMatch|errorResponse' -A 20 -B 5 src | sed -n '1,260p'

Repository: mash-up-kr/Team-MINO-Node

Length of output: 18663


required 배열을 추가해 Swagger 응답 스키마를 실제 타입과 맞춰주세요 coordinateSchema, geoCandidateSchema, extractedPlaceSchema, placeMatchSchema, placeMatchListResponseApiSchema, errorResponseApiSchema 모두 required가 없어 응답 필드가 전부 선택적으로 표시됩니다. 특히 geoCandidateSchema는 GeoCandidate에 맞춰 provider, providerPlaceId, placeName, address, coordinate만 필수로 두고 나머지는 제외하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/modules/place/place.dto.ts` around lines 19 - 77, 각 스키마에 실제 응답 타입과 일치하는
required 배열을 추가하세요. coordinateSchema, geoCandidateSchema, extractedPlaceSchema,
placeMatchSchema, placeMatchListResponseApiSchema, errorResponseApiSchema의 필수
필드를 타입 정의에 맞춰 지정하고, 특히 geoCandidateSchema는 provider, providerPlaceId, placeName,
address, coordinate만 required로 설정하며 distance, mapUrl, phone, category는 제외하세요.

@KKardy KKardy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

구두로 말씀 드렸고, 미리 승인 드리겠습니다 🙇

@KKardy

KKardy commented Jul 25, 2026

Copy link
Copy Markdown
Member

@minsour
요거 머지 안하시는 이유가 있나요? 👀

@minsour

minsour commented Jul 26, 2026 •

Copy link
Copy Markdown
Member Author

요거 머지 안하시는 이유가 있나요? 👀

@KKardy
요 PR이 e2e 유기적 연동 작업이었는데 api 호출 중간 ai service 쪽에서 에러가 나서 안하고 있었네용
우선 머지시키고 브랜치 분리해서 더 보겠습니다ㅎㅎ

@minsour
minsour merged commit b256790 into main Jul 26, 2026
7 checks passed
@minsour
minsour deleted the feature/GM-88-instagram-scrap-e2e branch July 26, 2026 06:57
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.

2 participants