Skip to content

[Refactor/#153] API·도메인 조회 코드를 shared 폴더 구조로 정리 - #154

Merged
sangrae2325 merged 9 commits into
mainfrom
refactor/#153-shared-folder-structure
Nov 4, 2026
Merged

sangrae2325 merged 9 commits into
mainfrom
refactor/#153-shared-folder-structure

Conversation

@sangrae2325

@sangrae2325 sangrae2325 commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

#️⃣연관된 이슈

🎯 해결하려는 문제가 무엇인가요?

요청 코드가 src/lib/api/에, 도메인 조회가 src/entities/<도메인>/<도메인>Api.ts 한 파일에 key·조회·mutation이 같이 들어 있다. 실 API를 붙이면 도메인마다 응답 검사·변환 코드가 더해지는데, 지금 구조로는 한 파일이 계속 커지고 서버 코드와 서버와 상관없는 도구(lib/)가 섞인다.

❓ 왜 해결해야 하나요?

사물함부터 실 API 연동을 시작한다. 연동하면서 옮기면 파일 이동과 로직 변경이 한 diff에 섞여 리뷰가 어렵고, 도메인마다 다른 PR에서 각자 옮기게 된다. 연동 전에 위치·이름만 한 번에 정리한다. 화면 동작은 바뀌지 않는다.

⭐ 어떻게 해결했나요?

커밋을 단계별로 나눴다. 1·2는 옮기기만 해서 "Files changed"에서 이동(rename)으로 보인다.

1. lib/api → shared/api (8ce942d)

src/shared/api/  api.types.ts(← types.ts) · client.ts · errors.ts · token.ts · index.ts(새로)
  • index.ts로 모아 export — shared/api 밖(queryClient 등)은 @/shared/api로만 가져온다. 안쪽 파일끼리는 순환 import를 피하려고 파일을 직접 가져온다

2. entities → shared/entities (b338d3f) — 도메인 11개 폴더째 이동, import 경로만 수정

3. 도메인 파일 역할별 분리 (8adec02)

lockers/  lockersApi.ts → lockersQueries.ts (조회·mutation)
                         + lockersKeys.ts    (조회 key만)
          types.ts       → lockersTypes.ts
          lockersMock.ts → lockersMock.ts (그대로)
  • key를 따로 두면 다른 도메인이 캐시를 무효화할 때 조회 파일 전체를 가져오지 않아도 된다
  • 예외: auth는 key가 없어 authQueries·authTypes·authMock·session.ts, search는 목데이터가 없어 searchKeys·searchQueries·searchTypes

4. 컨벤션 문서 (7951425, c6874eb) — coding-style.md 폴더 구조·데이터 로딩 절, wds-component-usage.md 경로 3곳. 응답 변환은 기존대로 화면의 select로 하고, 여러 화면이 같은 변환을 쓰면 변환 함수를 shared/entities/<도메인>/에 두는 한 줄만 더했다

🧩 이 PR의 한계 & 트레이드오프

  • 파일 이동이 많아 diff가 크다(약 100개 파일). 대부분 import 경로 한두 줄이다
  • lib/는 남는다 — queryClient·mockupApi·날짜 포맷·앱 브리지처럼 서버와 상관없는 도구만 남긴다
  • zod 응답 검사는 아직 넣지 않았다(아래 대안 참고)

⛓️ 기존 기능에 미치는 영향

🔀 Edge Case & 실패 시나리오

  • 옮기면서 Biome import 정렬이 외부 라이브러리와 @/ 사이 빈 줄을 지운 곳이 있었다 — 원래 빈 줄이 있던 파일만 골라 되살렸다(원래 없던 파일은 그대로)
  • 확인: tsc -b --noEmit·biome ci(기존 main.tsx 경고 1건)·vite build 통과, 브라우저(375×812)에서 홈·챗봇·설정·검색·행사 목록/상세/없는 행사/신청내역·내 피드백·사물함 배정·알림·학생회비 화면 콘솔 에러 없음

📋 검토한 대안과 선택 이유

  • 파일 이름 점 구분(lockers.queries.ts) — 레포의 다른 파일(homeMock.ts·eventsApplication.ts)이 camelCase라 이름 규칙을 하나로 두려고 camelCase로 했다
  • 도메인 폴더 단수(locker) — terminology.md의 코드 용어가 복수(lockers, 서버 경로 /v1/app/lockers와 같음)이고 features/·라우트도 복수라 그대로 뒀다
  • zod를 지금 넣기 — 목데이터는 서버 응답이 아니라 화면 모양이라 지금 스키마를 만들면 서버와 다른 계약이 된다. 실 API를 붙이는 도메인부터 <도메인>Queries.ts에 넣기로 문서에 적었다
  • 응답 → 화면 모양 변환을 queryFn 안에서 — 한 곳에서 바꾸는 장점이 있지만, 같은 데이터를 여러 화면이 다른 모양으로 쓰고(내 납부 상태 → 학생회비 화면·행사 상세) 캐시가 Swagger 응답과 같아야 setQueryData·디버깅이 단순해서 기존 규칙(화면의 select)을 유지했다. #151도 이 규칙으로 연동했다

💬 리뷰 포인트

  • [c] zod는 연동하는 도메인부터 넣는다는 규칙 — coding-style.md 데이터 로딩 절
  • [a] 3단계 분리 커밋에서 <도메인>Keys.ts의 주석이 원래 key 위에 있던 그대로 옮겨졌는지

@sangrae2325 sangrae2325 self-assigned this Nov 3, 2026
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a1a02691-b187-4a5e-a615-f0e28ea8ca57
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@sangrae2325
sangrae2325 marked this pull request as ready for review November 3, 2026 14:24

@xeoxxn xeoxxn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

주석에 옛 경로(entities/...)가 남아 있어서 shared/entities/...로 맞춰 주세요.

homeMock.ts L43·53·71·118

- // applicationId는 신청내역 목데이터(entities/events)의 신청완료 건으로 맞춘다. 홈 행 이름(Figma 홈 문구)과
+ // applicationId는 신청내역 목데이터(shared/entities/events)의 신청완료 건으로 맞춘다. 홈 행 이름(Figma 홈 문구)과
- // 납부내역의 상태(entities/fee)에 홈에서만 보이는 미납을 더한다
+ // 납부내역의 상태(shared/entities/fee)에 홈에서만 보이는 미납을 더한다
- // noticeId는 공지 목데이터(entities/notices, 1~5번)에 있는 공지로 맞춘다. 배너 문구와 공지 내용은
+ // noticeId는 공지 목데이터(shared/entities/notices, 1~5번)에 있는 공지로 맞춘다. 배너 문구와 공지 내용은
- // 행사 목데이터(entities/events)의 모집중 행사
+ // 행사 목데이터(shared/entities/events)의 모집중 행사

LockersMineContent.tsx L21

- // 내 칸은 배정 정보(entities/lockers)의 칸 이름 하나로 정한다 — 구역 칸 데이터의 isMine에 기대지 않고,
+ // 내 칸은 배정 정보(shared/entities/lockers)의 칸 이름 하나로 정한다 — 구역 칸 데이터의 isMine에 기대지 않고,

settings.ts L9

- // (`entities/users/`). 백엔드가 설정 전용 엔드포인트를 따로 내면 그때 사전에 추가하고 여기를
+ // (`shared/entities/users/`). 백엔드가 설정 전용 엔드포인트를 따로 내면 그때 사전에 추가하고 여기를

- 조회 기본값은 `lib/queryClient.ts`에 있다: 1분 안에 다시 들어온 화면은 요청 없이 캐시를 쓰고(`staleTime`), 실패는 네트워크·5xx만 한 번 더 시도한다(4xx는 다시 보내도 같다). 도메인마다 다르게 해야 하면 그 `queryOptions`에 덮어쓴다.
- 실 API 전까지 `queryFn`은 `<도메인>Mock.ts`의 목데이터를 `mockupResponse(() => data)`(`lib/mockupApi.ts`)로 돌려준다. 개발 서버에서는 스켈레톤을 확인할 수 있게 500ms 늦게 응답하고, 배포 빌드에서는 바로 응답한다. API가 붙으면 `queryFn` 안쪽만 `api.get(...)`으로 바꾼다.
- 데이터를 바꾸는 요청(신청 취소 등)은 API 파일에 `use<동작>Mutation` 훅(`useCancelEventApplicationMutation`)으로 두고, `onSuccess`에서 바뀐 조회 key를 `invalidateQueries`로 무효화한다(화면은 무효화를 모른다). 무효화 Promise를 돌려줘서 다시 받은 데이터가 들어온 뒤에 mutation이 끝나게 한다. 지금 화면에 없는데 돌아갔을 때 바로 보여야 하는 조회(신청내역 목록 등)는 `refetchQueries({ queryKey, exact: true })`로 그것만 같이 받는다 — `refetchType: "all"`은 열어 봤던 상세까지 전부 다시 받는다. 데이터가 이미 있는 조회는 다시 받는 동안 서스펜드되지 않고 지금 화면을 유지한다.
- 서버 응답 검사(zod 스키마)는 실 API를 붙이는 도메인부터 `<도메인>Queries.ts`에 넣는다. 목데이터는 서버 응답이 아니라 화면 모양이라, 미리 만든 스키마는 서버와 다른 계약이 된다.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

지금 실 API 연결해 둔 작업들은 머지 전에 이 규칙에 맞춰 zod 스키마를 넣어 수정하겠습니다.

Comment thread src/shared/api/index.ts Outdated
ApiResponse,
CursorSliceResponse,
PageResponse,
} from "@/shared/api/api.types";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

파일 이름을 camelCase로 통일하기로 했는데 api.types.ts만 점으로 구분돼 있어서, <도메인>Types.ts처럼 apiTypes.ts로 맞추면 좋을 것 같습니다.

- src/shared/api/api.types.ts
+ src/shared/api/apiTypes.ts

  // index.ts · client.ts · errors.ts
- from "@/shared/api/api.types";
+ from "@/shared/api/apiTypes";

Comment thread docs/conventions/coding-style.md Outdated
- 기능 기반(feature-based) 구조를 쓴다. `app/`(라우팅 껍데기)·`components/ui/`(공용 UI)·`hooks/`·`lib/`·`utils/`·`constants/`는 실제로 내용이 생길 때 만든다 — 빈 폴더를 미리 만들지 않는다.
- 화면 단위 기능이 생기면 `features/<기능>/`, 여러 화면이 공유하는 서버 계약(API·쿼리·타입)이 생기면 `entities/<도메인>/`을 그때 도입한다.
- 화면 단위 기능이 생기면 `features/<기능>/`, 여러 화면이 공유하는 서버 계약(API·쿼리·타입)이 생기면 `shared/entities/<도메인>/`을 그때 도입한다.
- 서버와 주고받는 코드는 `shared/`에 둔다 — 요청 클라이언트는 `shared/api/`, 도메인 조회는 `shared/entities/<도메인>/`. `lib/`에는 서버와 상관없는 도구(`queryClient`·날짜 포맷·앱 브리지 등)만 둔다.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

queryClient는 서버 캐시라 "서버와 상관없는 도구"라는 설명과 맞지 않는 것 같습니다. "요청을 직접 보내지 않는 도구"처럼 표현을 다듬거나 queryClient 위치를 조정하면 좋을 것 같습니다.

Suggested change
- 서버와 주고받는 코드는 `shared/`에 둔다 — 요청 클라이언트는 `shared/api/`, 도메인 조회는 `shared/entities/<도메인>/`. `lib/`에는 서버와 상관없는 도구(`queryClient`·날짜 포맷·앱 브리지 등)만 둔다.
- 서버와 주고받는 코드는 `shared/`에 둔다 — 요청 클라이언트는 `shared/api/`, 도메인 조회는 `shared/entities/<도메인>/`. `lib/`에는 요청을 직접 보내지 않는 도구(`queryClient`·날짜 포맷·앱 브리지 등)만 둔다.

@sangrae2325 sangrae2325 mentioned this pull request Nov 3, 2026
7 tasks
xeoxxn added a commit that referenced this pull request Nov 3, 2026
충돌은 회비 쪽 내용을 새 경로로 옮겨 풀었다(feeKeys·feeQueries 분리, feeMock 삭제, import 경로, coding-style 데이터 로딩 절).
@sangrae2325
sangrae2325 added this pull request to stack #157 November 3, 2026 17:21
@sangrae2325 sangrae2325 mentioned this pull request Nov 4, 2026
6 tasks
* refactor: 빌릴게 코드 용어를 bililge에서 billilge로 변경

* docs: 용어 사전과 컨벤션 문서의 빌릴게 코드 용어를 billilge로 변경
@sangrae2325
sangrae2325 merged commit b1aaf2e into main Nov 4, 2026
1 check passed
jjunh33 added a commit that referenced this pull request Nov 4, 2026
main의 shared 폴더 구조 정리(#154)에 맞춰 이메일 인증 API·목·타입이 shared/entities/auth로 합쳐졌고, AuthSignupScreen의 import와 문서의 경로·시작 단계 설명을 정리했다.
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.

API·도메인 조회 코드를 shared 폴더 구조로 정리

2 participants