Skip to content

feat(place): 장소에 저장된 게시물을 모아보는 페이지 추가 - #117

Merged
yunyoungyee merged 6 commits into
mainfrom
fix/multi-post
Aug 18, 2026
Merged

feat(place): 장소에 저장된 게시물을 모아보는 페이지 추가#117
yunyoungyee merged 6 commits into
mainfrom
fix/multi-post

Conversation

@yunyoungyee

Copy link
Copy Markdown
Member

1. 요약

  • 한 장소에 저장된 게시물이 여러 건일 때 장소 시트에 다 담지 않고 별도 페이지(/place/{placeId}/posts)로 분리했습니다. (Figma 8월 19일 작업 165:18106)
  • 그 과정에서 GET /api/v1/places/{placeId} 가 주는 게시물 페이지 정보(hasNext·totalElements)를 프론트가 통째로 버리고 있는 걸 발견해 함께 연동했습니다. 기존에는 21건째부터 어떤 화면에서도 볼 수 없었고 개수도 최대 20에서 멈춰 있었습니다.
  • 무한 스크롤 sentinel 코드가 세 번째로 복사될 자리라 공용 훅으로 뽑았습니다.

2. 작업 내용

e368ab3 장소에 저장된 게시물이 여러 건이면 별도 페이지로 분리

  • 장소 시트의 저장 게시물 섹션을 게시물 수로 나눴습니다. 1건이면 기존처럼 카드를 펼치고, 2건 이상이면 저장된 게시물 N > 헤더 + 가로 카드 목록만 둡니다.
  • 헤더는 제목·개수·화살표를 한 버튼으로 묶어 줄 어디를 눌러도 게시물 페이지로 이동합니다.
  • 가로 카드(SavedPostTile)는 시안 List(165:20658) — 167x208 썸네일 + 제목 + 계정 · N Places. 이미지가 2장 이상인 게시물은 썸네일 우상단에 여러 장 표시를 얹습니다.
  • 새 페이지는 시트와 같은 SavedPostCard 를 쓰되 제목 줄만 끕니다(title={null}) — 화면 헤더가 이미 "저장된 게시물"이라고 말하기 때문입니다. 제목 줄이 사라지면 그 줄이 갖던 상단 16px 을 태그 줄이 대신 받습니다.
  • 장소 상세의 얇은 게시물 → 카드용 Post 변환을 map/lib/placePost.ts 로, 게시물 상세 병렬 조회(usePostDetails)를 post/api/queries.ts 로 올려 두 화면이 같은 캐시를 공유합니다.

d9adb85 무한 스크롤 sentinel 훅 추출

  • 목록 끝 sentinel 을 IntersectionObserver 로 관찰하는 12줄 effect 가 ArchiveDetailPageSharedArchivePage 에 그대로 복붙돼 있었습니다.
  • shared/lib/useInfiniteScrollSentinel 로 옮기고 두 화면을 각각 한 줄로 줄였습니다. 옵션도 인터페이스도 새로 만들지 않은 순수 이동이라 동작은 그대로입니다.

be43afd 장소 게시물 페이지네이션 연동

  • fetchPlacePosts(placeId, page) 추가. 장소별 게시물 전용 엔드포인트가 없어서 장소 상세를 page 파라미터와 함께 다시 부르는 형태입니다.
  • usePlacePosts 무한 쿼리로 게시물 페이지에 무한 스크롤을 붙였습니다. 이 페이지가 쓰던 usePlaceDetail 호출은 걷어냈습니다 — 실제로 쓰는 건 posts 뿐이라 진입 요청이 1회로 줄어듭니다.
  • PlaceDetail.postsTotal(= totalElements) 추가. 시트 헤더는 첫 페이지 건수가 아니라 이 값을 찍습니다. 시트의 가로 목록은 미리보기라 첫 페이지(최대 20건)까지만 그립니다.

3. 기술적 결정

주요 결정 사항

  • 결정 내용: 시트가 쓰는 usePlaceDetail 은 그대로 두고, 게시물 페이지 전용으로 usePlacePosts 무한 쿼리를 따로 뒀습니다. 쿼리 키는 ['map','detail',placeId,'posts'] 로 기존 detail 키 접두사 아래에 뒀습니다.
  • 선택 이유: usePlaceDetail 은 지도 핀과 이동(panTarget)까지 같은 캐시를 보고 있어서, 이걸 무한 쿼리로 바꾸면 지도 동작까지 파급됩니다. 키를 detail 아래 두면 북마크·메모·연결끊기가 이미 하고 있는 invalidateQueries(detail(placeId)) 가 접두사 매칭으로 이 목록까지 함께 갱신해 줍니다(추가 배선 없음).
  • 검토가 필요한 부분:
    • 시트에서 페이지로 넘어갈 때 places/{placeId} 가 1회 중복됩니다(키가 달라서). initialData 로 캐시를 수동 seed 하면 없앨 수 있지만 staleTime 이 30초라 곧 재요청될 값이라 이득이 없다고 판단했습니다.
    • 페이지를 넘길 때마다 사진·태그·영업시간까지 실린 장소 상세 전체가 재전송됩니다. /api/v1/places/{placeId}/posts 같은 전용 엔드포인트가 생기면 fetchPlacePosts 만 갈아끼우면 됩니다.
    • 게시물 카드마다 posts/{postId} 를 부르는 N+1 구조는 이번에 건드리지 않았습니다. 시트의 가로 카드가 상세를 필요로 하는 건 이미지 장수연결된 장소 수 둘뿐이라, 서버가 PlacePostResponse 에 이 두 카운트만 실어주면 시트 쪽 fan-out 은 통째로 사라집니다. (BE 논의 필요)

Figma `8월 19일 작업`(165:18106) 반영.

장소 시트가 게시물마다 카드를 통째로 펼쳐 세로로 쌓던 걸 게시물 수로 나눈다.
한 건이면 지금처럼 카드를 펼치고, 여러 건이면 "저장된 게시물 N >" 헤더와
가로 카드 목록만 두고 전체는 `/place/{placeId}/posts` 로 넘긴다.
헤더는 제목·개수·화살표를 한 버튼으로 묶어 줄 어디를 눌러도 그 페이지로 간다.

- 가로 카드(`SavedPostTile`)는 시안 `List`(165:20658) — 167x208 썸네일 + 제목 +
  "계정 · N Places". 이미지가 2장 이상이면 우상단에 여러 장 표시를 얹는다.
- 새 페이지는 시트와 같은 `SavedPostCard` 를 쓰되 제목 줄은 화면 헤더가 대신하므로
  끈다(`title={null}`). 제목 줄이 없으면 그 줄이 갖던 상단 16px 을 태그 줄이 받는다.
- 장소 상세의 얇은 게시물 → 카드용 `Post` 변환을 `map/lib/placePost.ts` 로 빼
  시트와 새 페이지가 같이 쓴다.
- 게시물 상세 병렬 조회(`usePostDetails`)를 `post/api/queries.ts` 로 올려
  두 화면이 같은 캐시를 공유하게 했다. 다른 조회 훅과 같은 인증 가드도 함께 붙였다.
목록 끝 sentinel 을 IntersectionObserver 로 관찰해 다음 페이지를 당기는 12줄짜리
effect 가 `ArchiveDetailPage` 와 `SharedArchivePage` 에 그대로 복붙돼 있었다.
세 번째 사용처가 생기는 시점이라 `shared/lib/useInfiniteScrollSentinel` 로 옮긴다.

동작은 그대로다 — 옵션도 인터페이스도 새로 만들지 않고 위치만 옮겼다.
두 화면은 `useInfiniteQuery` 결과를 그대로 넘기고 ref 만 받는다.
`GET /api/v1/places/{placeId}` 의 `posts` 는 `page`/`size`(기본 20) 파라미터를 받는
페이지 응답인데, 프론트가 params 를 넘기지 않고 `items` 만 읽어 `hasNext`·
`totalElements` 를 버리고 있었다. 그래서 21건째부터는 어떤 화면에서도 볼 수 없었고
시트 헤더의 개수도 최대 20 에서 멈췄다. 서버가 이미 주는 값을 쓰게 한다.

- `fetchPlacePosts(placeId, page)` 추가. 장소별 게시물 전용 엔드포인트가 없어서
  장소 상세를 page 파라미터와 함께 다시 부르는 형태다.
- `usePlacePosts` 무한 쿼리로 게시물 페이지에 무한 스크롤을 붙였다. 이 페이지가 쓰던
  `usePlaceDetail` 호출은 걷어냈다 — 쓰는 건 posts 뿐이라 진입 요청이 1회로 줄어든다.
- 쿼리 키를 `detail` 접두사 아래에 둬서 북마크·메모·연결끊기의 기존 무효화가
  이 목록까지 함께 갱신하게 했다.
- `PlaceDetail.postsTotal`(= totalElements) 추가. 시트 헤더는 첫 페이지 건수가 아니라
  이 값을 찍는다. 시트의 가로 목록은 미리보기라 첫 페이지까지만 그린다.
…x/multi-post

# Conflicts:
#	apps/web/src/features/map/api/index.test.ts
#	apps/web/src/features/map/api/index.ts
#	apps/web/src/features/map/api/queries.ts
#	apps/web/src/features/map/components/PlaceDetail.tsx
#	apps/web/src/features/share/SharedArchivePage.tsx
@yunyoungyee yunyoungyee self-assigned this Aug 18, 2026
@vercel

vercel Bot commented Aug 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nook-client-web Ready Ready Preview Aug 18, 2026 7:17pm

@yunyoungyee
yunyoungyee merged commit 734bbc8 into main Aug 18, 2026
5 checks passed
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.

1 participant