Skip to content

[FEATURE] 폴더 API 연동#52

Merged
kbh0218 merged 7 commits into
devfrom
feat/#51-category-api
May 24, 2026
Merged

[FEATURE] 폴더 API 연동#52
kbh0218 merged 7 commits into
devfrom
feat/#51-category-api

Conversation

@kbh0218

@kbh0218 kbh0218 commented May 23, 2026

Copy link
Copy Markdown
Contributor

Closes #51

개요

폴더 화면에서 사용하던 mock 폴더 상태를 백엔드 Category API 기반 흐름으로 교체했습니다.

기존 context/folders-context.tsxMOCK_FOLDERS를 기준으로 폴더 생성, 이름 수정, 삭제를 로컬 상태에서만 처리하고 있었습니다. 이번 작업에서는 백엔드 LinClean-BE-spring의 폴더 API 개발 PR 기준으로 GET /api/v1/categories, POST /api/v1/categories, PATCH /api/v1/categories/{id}, DELETE /api/v1/categories/{id}를 실제 화면 흐름에 연결했습니다.

Category API는 Clerk 인증 토큰이 필요한 보호 API이므로, issue #41에서 정리한 공통 API 클라이언트 패턴을 사용했습니다. 기능별 API 파일에서는 API base URL을 새로 만들지 않고, fetch()Authorization 헤더를 직접 다루지 않도록 구성했습니다.

또한 폴더 생성, 삭제, 이름 수정, 폴더 내 링크 제외 흐름에서 사용자 안내 toast와 확인창을 정리하고, 저장 링크 목록과 폴더 목록의 상태가 함께 갱신되도록 보완했습니다.

주요 구현 내용

  • Category API 전용 파일 api/categories.ts 추가
  • GET /api/v1/categories 폴더 목록 조회 연동
  • POST /api/v1/categories 폴더 생성 연동
  • 폴더 생성 시 선택한 링크 목록을 linkIds로 함께 전달
  • 새 폴더 생성 시 기존 assignCategory 중복 호출 제거
  • PATCH /api/v1/categories/{id} 폴더명 수정 연동
  • DELETE /api/v1/categories/{id} 폴더 삭제 연동
  • 폴더 삭제 시 선행 assignCategory(..., null) 호출 제거
  • FoldersProvider 위치를 탭 layout 기준으로 정리
  • 폴더 목록 로딩, 빈 목록, API 에러 상태 처리
  • 폴더명 입력 후 다음 클릭 시 중복 폴더명 검증
  • 폴더 생성, 삭제, 이름 수정 성공 시 상단 toast 표시
  • 폴더 내 링크 제외 시 확인창 표시
  • 폴더 내 링크 제외 후 저장 링크 목록과 폴더 목록 refresh 처리
  • 폴더 상세 링크 카드의 제목 수정 흐름을 메인 링크 카드와 동일하게 연결
  • 홈 저장 링크 필터 칩에 실제 Category 목록 반영
  • 폴더명 수정 시 입력값이 현재 폴더명과 동일하면 저장 버튼 비활성화
  • 폴더명 수정 submit guard에도 동일 이름 검증 추가

파일별 역할

  • api/categories.ts: Category API 타입 및 생성/조회/수정/삭제 호출 함수 추가
  • context/folders-context.tsx: mock 폴더 상태를 Category API 기반 상태와 액션으로 교체
  • app/(tabs)/_layout.tsx: FoldersProvider 위치 조정
  • app/(tabs)/(folder)/_layout.tsx: 중복 provider 제거
  • app/(tabs)/(folder)/index.tsx: 폴더 목록 조회, 로딩/빈 목록/에러, 삭제 toast 처리
  • app/(tabs)/(folder)/index.tsx: 폴더명 수정 모달에서 현재 폴더명과 동일한 입력값일 때 저장 버튼 비활성화 처리
  • app/(tabs)/(folder)/folder-name.tsx: 폴더명 입력, 중복명 검증, 생성/수정 흐름 연결
  • app/(tabs)/(folder)/folder-url-select.tsx: 폴더 생성 시 선택 링크 linkIds 전달
  • app/(tabs)/(folder)/folder-add-url.tsx: 기존 링크의 폴더 추가 흐름 유지 및 폴더 목록 refresh 처리
  • app/(tabs)/(folder)/[id].tsx: 폴더 상세 링크 제외, 제목 수정, toast, refresh 처리
  • app/(tabs)/(home)/index.tsx: 링크 삭제 후 폴더 목록 refresh 처리
  • app/(tabs)/(home)/saved-links.tsx: 실제 Category 목록 기반 필터 칩 표시

해결한 이슈 목록

  • 현재 폴더 화면과 context/folders-context.tsx의 mock 상태 구조 확인
  • api/categories.ts 추가 및 Category API 타입/호출 함수 분리
  • Category API 호출에 authenticatedApiRequest 사용
  • 기능별 API 파일에서 API base URL 새로 생성하지 않음
  • 기능별 API 파일에서 fetch() 직접 호출하지 않음
  • 기능별 API 파일에서 Authorization 헤더 직접 주입하지 않음
  • GET /api/v1/categories 응답의 items 구조를 폴더 상태에 반영
  • POST /api/v1/categories 요청에 name, linkIds 전달
  • 새 폴더 생성 시 assignCategory 중복 호출 없이 linkIds 일괄 배치 기능 사용
  • PATCH /api/v1/categories/{id} 폴더명 수정 흐름 연결
  • DELETE /api/v1/categories/{id} 폴더 삭제 흐름 연결
  • 폴더 삭제 시 프론트의 불필요한 선행 assignCategory(..., null) 호출 제거
  • 폴더 생성/수정/삭제 후 저장 링크 목록과 폴더 목록이 일관되게 반영되도록 처리
  • 폴더 목록 로딩/빈 목록/API 에러 상태 처리
  • 중복 폴더명, 인증 실패, 네트워크 오류 등 실패 상황 사용자 안내 처리
  • SavedLinksProviderFoldersProvider 위치 검토 및 중복 생성 정리
  • 폴더 상세 화면의 기존 URL 추가/제거 흐름 유지
  • 폴더 상세 링크 카드의 제목 수정 로직을 메인 화면 링크 카드와 동일하게 처리
  • 폴더 생성/삭제/이름 수정 toast 처리
  • 폴더에서 링크 제외 시 실제 URL 삭제가 아닌 폴더 제외 의미의 확인창 표시
  • 폴더명 수정 시 현재 폴더명과 동일한 경우 수정 버튼 비활성화
  • 폴더명 수정 버튼 비활성화 조건과 실제 API 호출 방어 조건 일치

체크 사항

  • 커밋/코딩 컨벤션에 맞게 작성
  • 프론트 API 클라이언트 사용 규칙 준수
  • 폴더명 수정 시 빈 값, 동일 이름, 수정 중 상태에서 저장 요청이 발생하지 않도록 처리
  • Category API 파일에서 직접 fetch() 호출 없음
  • Category API 파일에서 직접 API base URL 생성 없음
  • Category API 파일에서 직접 Authorization 헤더 주입 없음
  • Category API 파일에서 { data: ... } 응답 직접 unwrap 없음
  • 보호 API 호출 전 /auth/me 수동 선호출 없음
  • DELETE /api/v1/categories/{id}204 No Content 응답 처리

참고

폴더 삭제 시 연결된 저장 링크의 categoryId 정리는 백엔드에서 처리하므로, 프론트에서는 별도의 선행 링크 이동 API를 호출하지 않습니다.

기존 저장 링크의 폴더 이동/제거 흐름은 PATCH /api/v1/saved-links/{id}/category 기반 흐름을 유지했습니다.

폴더 생성 시 선택한 링크가 있는 경우에는 POST /api/v1/categories 요청의 linkIds를 사용해 한 번에 연결되도록 처리했습니다.

스크린샷

  • 저장한 링크에서 폴더별로 뜨는 모습입니다.
image
  • 폴더 이름 생성 단계에서 중복을 체크하는 화면입니다.
image
  • 폴더명 수정 시 같은 이름은 저장버튼이 비활성화 됩니다.
image
  • 데이터베이스에도 잘 들어온 모습입니다.
image

@kbh0218 kbh0218 requested review from minsoo0506 and sunm2n May 23, 2026 09:17
@kbh0218 kbh0218 self-assigned this May 23, 2026
@kbh0218 kbh0218 added the feature 기능개발 label May 23, 2026
if (selectedIds.size > 0) {
assignCategory([...selectedIds], newId);
}
await addFolder(name, [...selectedIds]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

addFolder 성공 후 refreshLinks 실패 시 중복 폴더 생성 위험

현재 코드:

  await addFolder(name, [...selectedIds]);  // 서버에 폴더 생성 + 로컬 상태 갱신 ✓
  await refreshLinks();                     // 실패하면 catch로 이동
  router.dismissAll();                      // 실행 안 됨
  router.replace({...});                   // 실행 안 됨

addFolder 성공 후 refreshLinks()가 throw하면:

  1. "폴더 생성 실패" Alert 표시 — 하지만 폴더는 이미 서버에 생성됨
  2. isCreating = false로 복구, 화면 유지 
  3. 사용자가 다시 만들기 버튼 누름 → addFolder 재호출 → 서버에 중복 폴더 생성

folder-name.tsx의 중복 이름 검사는 로컬 folders 상태 기준이라 addFolder가 이미 상태에 추가했으므로 감지되지만, folder-url-select.tsx 화면에서는 이름 검사가 없어 직접 재시도하면 통과됩니다.

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.

피드백 감사합니다!
코드 흐름을 다시 확인해봤는데, 현재 구현 기준으로는 말씀하신 중복 생성 시나리오는 발생하지 않는 것으로 판단했습니다.

folder-url-select.tsx에서는 addFolder 이후 refreshLinks()를 호출하고 있지만, 실제 refreshLinks() 구현은 내부에서 fetchSavedLinks 실패를 catch한 뒤 setErrorMessage만 호출하고 다시 throw하지 않습니다.

따라서 refreshLinks()가 API 호출에 실패하더라도 folder-url-select.tsx의 catch로 이동하지 않고, 이후 router.dismissAll() / router.replace()가 그대로 실행됩니다. 즉 “폴더 생성 실패” Alert가 뜨고 화면에 남아 사용자가 다시 생성 버튼을 눌러 중복 생성되는 흐름은 현재 코드에서는 재현되지 않습니다.

다만 말씀하신 것처럼 addFolder 성공 이후 후속 작업까지 하나의 try/catch에 묶여 있는 구조는 오해의 여지가 있어 보입니다. 그래서 생성 성공 이후의 refreshLinks()는 폴더 생성 실패와 분리되도록 후속 작업으로 취급하는 방향으로 정리하겠습니다.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

확인 감사합니다!

@sunm2n sunm2n left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

수고하셨습니다! 바로 머지해도 될 거 같습니다!

@kbh0218 kbh0218 merged commit 2c0488a into dev May 24, 2026
@kbh0218 kbh0218 deleted the feat/#51-category-api branch May 24, 2026 10:41
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] 폴더 API 연동

2 participants