-
Notifications
You must be signed in to change notification settings - Fork 46
[1팀 도희정] Chapter 3-3 기능 중심 아키텍처와 프로젝트 폴더 구조 #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dev-learning1
wants to merge
17
commits into
hanghae-plus:main
Choose a base branch
from
dev-learning1:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- Add jotai for global state management - Add @tanstack/react-query for server state management - Add @types/node for path module types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Add path aliases (@/*) in tsconfig.app.json - Configure Vite path resolution - Add CSS module type declaration in vite-env.d.ts - Include vite-env.d.ts in tsconfig to fix CSS import errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Add type definitions for all entities (Post, Comment, User, Tag) - Create API client with REST methods (get, post, put, patch, delete) - Implement highlight text utility for search functionality - Add shared UI components (Button, Input, Card, Table, Dialog, Select) - Move Header and Footer to shared/ui 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Post entity: - API functions for CRUD operations and filtering - React Query hooks (useQueryPosts, useMutationPostAdd, etc.) - PostCard UI component Comment entity: - API functions for comment CRUD and like operations - React Query hooks (useQueryComments, useMutationCommentAdd, etc.) - CommentItem UI component User entity: - API function for user details - React Query hook (useQueryUser) Tag entity: - API function for fetching tags - React Query hook (useQueryTags) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Global state management (Jotai): - Create atoms for search, filter, sort, and pagination state Post features: - PostAddDialog: Add new post functionality - PostEditDialog: Edit existing post functionality - PostSearchBar: Search posts with highlighting Comment features: - CommentAddDialog: Add new comment functionality - CommentEditDialog: Edit existing comment functionality All features use TanStack Query hooks from entities layer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
PostTable widget: - Display posts in table format - Integrate PostCard, edit/delete actions - Handle post selection for details PostDetail widget: - Show post details with comments - Integrate comment CRUD features - Support comment like functionality UserModal widget: - Display user information in modal - Fetch user details on demand 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Reduce from 700+ lines to 230 lines - Use Jotai atoms for global state (search, filter, sort, pagination) - Use TanStack Query hooks for server state - Compose features and widgets for clean separation - Sync state with URL parameters - Handle multiple query modes (normal, search, tag filter) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Create QueryProvider with TanStack Query configuration - Configure query defaults (retry, refetchOnWindowFocus, staleTime) - Update App.tsx to use new providers and FSD paths - Wrap application with QueryProvider 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Remove src/components/Header.tsx (moved to shared/ui) - Remove src/components/Footer.tsx (moved to shared/ui) - Remove src/components/index.tsx (replaced by shared/ui) All components have been reorganized into FSD structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Add getUsers() API to fetch all users with username and image - Add useQueryUsers() hook with 5-minute cache - Enable displaying author info in posts without redundant API calls This improves performance by fetching users once and reusing the data across multiple posts instead of embedding user data in each post response. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Add likePost() API to increment post likes - Add dislikePost() API to increment post dislikes - Use PATCH method to update reactions field Enables interactive like/dislike functionality on posts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Replace invalidateQueries with setQueryData for immediate UI updates: Post CRUD operations: - Add: Insert new post at top of cache - Update: Replace specific post in cache - Delete: Remove specific post from cache Like/Dislike operations: - Use optimistic updates (onMutate) for instant UI feedback - Update all cached queries containing the post - Remove onSuccess to prevent server response overriding UI Why this approach: - Mock API environment doesn't persist changes reliably - Optimistic updates provide better UX - Eliminates unnecessary refetch delays 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Replace invalidateQueries with setQueryData for immediate UI updates: Comment CRUD operations: - Add: Insert new comment at top of cache - Update: Replace specific comment in cache - Delete: Remove specific comment from cache Comment like operation: - Use optimistic updates (onMutate) for instant UI feedback - Cancel ongoing queries to prevent race conditions - Remove onSuccess to prevent server response overriding UI Why this approach: - Mock API environment doesn't persist changes reliably - Optimistic updates provide instant user feedback - Eliminates delay between action and UI update - Prevents UI flickering from refetch 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Remove PostCard component (inline the post display logic) - Add like/dislike buttons with click handlers - Display post title, tags, author, and reactions in table cells - Enable tag filtering by clicking on tag badges Why this change: - PostCard was only used in one place (not reusable) - Direct rendering in table cells improves readability - Like/dislike buttons now functional instead of read-only 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Fetch users once with useQueryUsers and merge with posts - Prevent duplicate URL updates with comparison logic - Add replace: true to navigate() to avoid history pollution Changes: 1. User data handling: - Use useQueryUsers() to fetch all users once - Merge author data in getCurrentPosts() instead of in API - Reduces redundant API calls 2. URL synchronization: - Compare new URL params with current before navigate - Only update URL if params actually changed - Prevents unnecessary re-renders and navigation events 3. Search query in URL: - Add searchQuery to URL sync useEffect dependencies - Ensures search state persists in URL 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
과제 체크포인트
기본과제
목표 : 전역상태관리를 이용한 적절한 분리와 계층에 대한 이해를 통한 FSD 폴더 구조 적용하기
체크포인트
심화과제
목표: 서버상태관리 도구인 TanstackQuery를 이용하여 비동기코드를 선언적인 함수형 프로그래밍으로 작성하기
체크포인트
최종과제
과제 셀프회고
이번 과제를 통해 이전에 비해 새롭게 알게 된 점이 있다면 적어주세요.
본인이 과제를 하면서 가장 애쓰려고 노력했던 부분은 무엇인가요?
핵심 성과:
📂 프로젝트 폴더 구조
🏗️ 레이어별 설계 원칙과 의도
1️⃣ app - 애플리케이션 레이어
역할: 애플리케이션 진입점 및 전역 설정 관리
구현 내용:
QueryProvider.tsx: TanStack Query 클라이언트 설정staleTime: 60초- 1분간 데이터를 신선하게 유지retry: 1- 실패 시 1번만 재시도refetchOnWindowFocus: false- 윈도우 포커스 시 자동 갱신 비활성화설계 의도:
2️⃣ pages - 페이지 레이어
역할: 라우팅 단위의 최상위 컴포넌트 (데이터 조합 및 레이아웃 구성)
구현 내용:
PostsManagerPage.tsx(230줄)설계 의도:
3️⃣ widgets - 위젯 레이어
역할: 재사용 가능한 복합 UI 블록 (여러 entities와 features 조합)
구현 내용:
PostTable.tsx: 게시물 목록 테이블PostDetail.tsx: 게시물 상세 및 댓글UserModal.tsx: 사용자 정보 모달설계 의도:
widgets vs features 구분 기준:
4️⃣ features - 피처 레이어
역할: 사용자 행동 및 인터랙션 처리 (비즈니스 로직)
구현 내용:
A. Post 관련 기능
PostAddDialog.tsx: 게시물 생성 다이얼로그useMutationPostAdd()사용PostEditDialog.tsx: 게시물 수정 다이얼로그useMutationPostUpdate()사용B. Comment 관련 기능
CommentAddDialog.tsx: 댓글 작성CommentEditDialog.tsx: 댓글 수정C. 검색 및 필터링
PostSearchBar.tsx: 검색 UIstore.ts(Jotai atoms):설계 의도:
5️⃣ entities - 엔티티 레이어
역할: 비즈니스 엔티티의 데이터 모델, API, UI 표현
구조: api / model / ui 3단 분리
구현 내용:
A. Post 엔티티
api: REST API 호출 함수
getPosts(),searchPosts(),getPostsByTag()createPost(),updatePost(),deletePost()likePost(),dislikePost()model: TanStack Query 훅 (src/entities/post/model/usePost.ts:7-189)
useQueryPosts()- 게시물 목록 조회useQueryPostsSearch()- 검색useQueryPostsByTag()- 태그 필터링useMutationPostAdd()- 생성 (캐시 직접 업데이트)useMutationPostUpdate()- 수정 (캐시 직접 업데이트)useMutationPostDelete()- 삭제 (캐시 직접 업데이트)useMutationPostLike()- 좋아요 (낙관적 업데이트)useMutationPostDislike()- 싫어요 (낙관적 업데이트)ui: Post 표현 컴포넌트
B. Comment, User, Tag 엔티티
설계 의도:
중요한 설계 결정: api/model 분리 이유
6️⃣ shared - 공유 레이어
역할: 프로젝트 전역에서 사용되는 공통 코드
구현 내용:
A. types - 타입 정의
B. api/client - REST API 클라이언트
C. ui - 기본 UI 컴포넌트
D. lib - 유틸리티 함수
highlightText(): 검색어 하이라이팅설계 의도:
🔄 상태 관리 전략
핵심 원칙: 서버 상태와 클라이언트 상태 명확히 분리
1. 서버 상태 (TanStack Query)
대상: API로부터 가져오는 모든 데이터
전략:
useQuery: 데이터 조회 및 캐싱useMutation: 데이터 변경2. 클라이언트 상태 (Jotai)
대상: UI 상태 및 사용자 인터랙션 상태
searchQueryAtom)selectedTagAtom)paginationAtom)sortOrderAtom)장점:
3. URL 상태 (선택적)
왜 이렇게 분리했는가?
⚡ TanStack Query 캐시 최적화 전략
문제 상황
Mock API 환경에서는 실제 데이터베이스가 없어 서버 응답을 신뢰할 수 없음.
invalidateQueries로 refetch하면 변경 사항이 반영되지 않은 기존 데이터를 다시 가져옴.해결 방법:
setQueryData를 이용한 직접 캐시 갱신1. CRUD 작업 (Post/Comment 생성, 수정, 삭제)
장점:
2. 낙관적 업데이트 (Like/Dislike)
장점:
3. 전체 캐시 전략 요약
useQuerysetQueryDatasetQueryDatasetQueryDatauseQuery+ 5분 캐시아직은 막연하다거나 더 고민이 필요한 부분을 적어주세요.
마지막 [리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문] 에 적힌 부분
이번에 배운 내용 중을 통해 앞으로 개발에 어떻게 적용해보고 싶은지 적어주세요.
챕터 셀프회고
클린코드: 읽기 좋고 유지보수하기 좋은 코드 만들기
결합도 낮추기: 디자인 패턴, 순수함수, 컴포넌트 분리, 전역상태 관리
응집도 높이기: 서버상태관리, 폴더 구조
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문
좋아요(낙관적 업데이트)
추가/수정/삭제