-
Notifications
You must be signed in to change notification settings - Fork 1
[Init] Zustand 초기 세팅 #21
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
Conversation
🚀 빌드 결과✅ 린트 검사 완료 |
odukong
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FSD 구조에 맞춰서 storage에 접근하는 로직은 shared/lib로, storage와 로그인 여부 싱크를 맞춰주는 로직은 shared/model로 분리하신 점 구조적으로 좋은 선택같아요!
나중에 토큰 저장방식이 바뀌더라도 store 로직은 수정하지 않아도 되니 관리하기 더 수월해질 것 같습니다 수고 많으셨어요🙌🏻🩷
몇 가지 코멘트 남겨두었으니 시간 나실 때 확인해주세요 ♪(´▽`)
src/shared/model/auth/auth.store.ts
Outdated
| type AuthState = { | ||
| isLoggedIn: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 AuthState 타입을 type으로 선언해주셨는데, 객체 타입의 확장성 측면이나 interface 사용을 지향하고 있는 Comfit 컨벤션 통일성을 위해 interface로 수정하는 건 어떨까요?
src/shared/model/auth/auth.store.ts
Outdated
| isLoggedIn: false, | ||
| actions: { | ||
| login: (accessToken) => { | ||
| tokenStorage.set(accessToken); | ||
| set({ isLoggedIn: true }); | ||
| }, | ||
| logout: () => { | ||
| tokenStorage.clear(); | ||
| set({ isLoggedIn: false }); | ||
| }, | ||
| syncFromStorage: () => { | ||
| const token = tokenStorage.get(); | ||
| set({ isLoggedIn: Boolean(token) }); | ||
| }, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syncFromStorage를 호출하여 storage 토큰과 전역 상태를 동기화하는 방향으로 구현해주셨는데,
useAuthStore는 isLoggedIn를 false로 초기화해두었기 때문에 App.tsx의 useEffect에서 syncFromStorage로 로그인 여부를 최신화(ex. false > true)하는 과정에서 false인 상태가 사용자에게 보여진 다음에 변경된 true상태가 보여지는 현상이 일어날 수도 같아요! (로그인 상태인데도 헤더의 로그인 버튼이 잠시 보인다거나 하는 식으로요!)
스토리지는 동기적으로 값을 가져오는만큼, 아래처럼 store 초기값 할당 시점에 바로 동기화시키는 방법은 어떨까요?
isLoggedIn: !!tokenStorage.get(),
hummingbbird
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
목적에 따라 lib/model 위치 구분해서 파일 생성한 점 저도 좋은 거 같습니다~ 다만 shared 레이어의 각 세그먼트 내부에서는 이미 레이어 자체가 전역 공통 영역이라는 의미를 가지기 때문에, 그 안에서 다시 auth 폴더로 한 번 더 감싸지 않아도 책임이 충분히 드러난다고 생각해요! 다른 분들 의견도 들어보고 합의하면 좋을 거 같습니다
코리 한 번 확인해주시고 수빈이가 남긴 코리 반영하고 바로 머지해도 될 거 같아요 수고하셨어요 !! 🙇♀️🙇♀️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 파일 이름은 자칫 '토큰 값들을 모아둔 상수 파일' 정도로 느껴질 수 있을 거 같아요! 의미가 더 드러나게 token-storage.ts로 수정해도 좋을 거 같습니다~
qowjdals23
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zustand 초기 세팅하느라 수고하셨습니다 ! pr 구체적으로 작성해주셔서 이해하기 너무 편하네요 !!!
auth 쪽 공개 API를 한 번 모아두고, app 레이어에서도 store 진입점을 따로 정리해둔 덕분에 import 동선도 깔끔해진 느낌이고 ! 토큰은 storage 유틸로 따로 빼두고, store는 isLoggedIn만 들고 가면서 login / logout / syncFromStorage로 저장/삭제/동기화 흐름을 딱 정리해둔 게 이해하기도 쉽고 이후에 기능 붙이기도 편할 것 같네요 !!
너무 수고 많으셨습니다 ❤️🔥
|
잘 반영된 거 같습니다~ 어푸할게용 ~👼👼 (앗차차 충돌 해결 해주시오 !!) |
| isLoggedIn: Boolean(tokenStorage.get()), | ||
| actions: { | ||
| login: (accessToken) => { | ||
| tokenStorage.set(accessToken); | ||
| set({ isLoggedIn: true }); | ||
| }, | ||
| logout: () => { | ||
| tokenStorage.clear(); | ||
| set({ isLoggedIn: false }); | ||
| }, | ||
| syncFromStorage: () => { | ||
| const token = tokenStorage.get(); | ||
| set({ isLoggedIn: Boolean(token) }); | ||
| }, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isLoggedIn을 store 초기화 시점에 이미 tokenStorage.get()으로 최신 토큰 상태를 가져오고 있기 때문에,
토큰 상태에 대해 싱크를 맞춰주는 syncFromStorage() 액션 메서드는 중복된 기능을 수행하게 되는 것 같아 해당 메서드는 제거하는 방향은 어떨까요? :-O
코리 내용은 잘 반영된 것 확인했습니당!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
말씀 주신 것처럼 store 초기화 시점에 이미 storage와 동기화가 이루어지고 있어 syncFromStorage 액션은 중복 책임으로 판단되어 제거했습니다! 코멘트 감사합니다 🙇♀️
✏️ Summary
Comfit 서비스의 Zustand 라이브러리 초기 세팅을 진행했습니다.
전역 상태를 최소화하는 팀 컨벤션에 맞춰, 토큰은
store가 아닌shared유틸에서 관리하고 Zustand에는 추후에 로그인 여부(isLoggedIn)만 유지할 수 있도록 구조를 설계했습니다.본 PR은 “초기 세팅”에 초점을 둔 작업으로, persist 방식(session/local)이나 세부 컨벤션은 추후 팀 내부 합의에 따라 변경될 수 있습니다.
📑 Tasks
✔️ Comfit은 왜 zustand를 도입했을까요?
Comfit 서비스에서는 전역 상태가 무분별하게 커지는 것을 방지하기 위해, **“전역 상태는 꼭 필요한 최소 범위만 관리한다”**는 방향으로 합의했습니다.
이에 따라 복잡한 설정이나 보일러플레이트가 필요한 상태 관리 도구 대신, 구조가 단순하고 사용 범위를 명확히 제한할 수 있는 Zustand를 전역 상태 관리 도구로 선택했습니다.
특히 로그인과 관련된 상태 중에서도,
accessToken자체를 전역 상태로 보관하는 것은 보안 및 책임 분리 측면에서 적절하지 않다고 판단했습니다. 따라서 UI 분기(로그인/비로그인 판단)에만 필요한isLoggedInboolean 값만 store에서 관리하고, 실제 토큰 값은 별도의 유틸 레이어에서 관리하는 구조로 결정했습니다.✔️ Comfit의 auth 전역 상태 초기 세팅이 적용된 FSD 폴더 구조
✔️ 토큰 관리 유틸 분리 (shared/lib)
토큰은 상태가 아닌 저장 매체와의 인터페이스 역할에 가깝다고 판단하여,
src/shared/lib/auth/token.ts파일로 분리해 관리하도록 했습니다.해당 유틸은
sessionStorage를 기반으로 하며,get / set / clear세 가지 역할만 수행하는 단일 책임 구조를 갖습니다. 이를 통해 store나 UI 레이어가 storage 구현 세부사항에 직접 의존하지 않도록 구현 했습니다.또한 현재는 세션 기반 로그인을 가정하고 있지만, 향후 자동 로그인 정책이나 보안 정책 변경으로
localStorage전환이 필요해질 경우에도 이 파일만 수정하면 되도록 확장 가능성을 고려한 구조로 설계했습니다.✔️ Auth 전역 store 구성 (shared/model)
로그인 여부는 여러 페이지와 레이아웃에서 공통으로 사용될 가능성이 높기 때문에, FSD 구조 기준으로
shared/model레이어에 auth store를 위치시키는 것으로 팀 합의했습니다.auth.store.ts에서는isLoggedIn을 두고login / logout / syncFromStorage를 정의했습니다.이때 store는 토큰 값을 직접 소유하지 않으며, 모든 토큰 접근은
tokenStorage유틸을 통해서만 이루어지도록 하여 역할과 책임을 명확히 분리하고자 했습니다.또한
index.ts파일을 통해 auth 모델의 **공개 API(barrel export)**를 구성하여, 외부에서는 항상@shared/model/auth경로로만 import 하도록 정리했습니다. 이를 통해 내부 파일 구조 변경 시에도 import 경로가 흔들리지 않도록 했습니다.✔️ app 레이어 store 엔트리 구성
src/app/store/index.ts는 전역 store를 실제로 구현하는 역할이 아니라, shared/model에 정의된 store들을 모아 export 하는 엔트리 포인트로만 사용됩니다.이 구조를 통해 app 레이어가 특정 store 구현에 직접 의존하지 않도록 하고, 추후 전역 store가 추가되더라도 import 구조나 진입 지점이 분산되지 않도록 대비하고자 하였습니다.
✔️ 앱 시작 시 로그인 상태 동기화
앱이 최초로 렌더링될 때, storage에 저장된 토큰 상태와 전역 store 상태를 일치시키기 위해
App.tsx에서syncFromStorage()를useEffect로 한 번만 호출하도록 구성했습니다.이를 통해
isLoggedIn = trueisLoggedIn = false로 상태가 자동 동기화됩니다.
새로고침, 직접 URL 진입 등 다양한 진입 케이스에서도 로그인 상태가 일관되게 유지되도록 하기 위해 이와 같이 초기 세팅을 진행하였습니다.
👀 To Reviewer
syncFromStorage()가 실행되었을 때 콘솔에 남는 로그를 확인하고자 하였습니다.sessionStorage에 토큰이 없는 상태에서 새로고침 →isLoggedIn = falseisLoggedIn = trueisLoggedIn = false간단한 방식으로 테스트해보았고, 현재 구조가 의도한 대로 동작함을 확인하고 테스트를 위한 관련 콘솔은 모두 삭제 후 commit한 상태입니다. 관련 DevTools 테스트 결과 캡쳐본은 하단 Screenshot 섹션에 함께 첨부하도록 하겠습니다 !!☺️
당연히 추후 로그인 세션 구조(토큰 관리 방식), persist 전략(session vs local), store의 세부적인 폴더 구조나 컨벤션 등은 실제 기능 구현을 진행하면서 팀 논의를 통해 충분히 변경될 수 있는 부분이라고 생각하고 있습니다. 그래서 해당 PR에서는 더 나은 방향이나 우려되는 지점이 있다면 부담 없이 의견 주시면 적극 반영하고 싶습니다. ❤️🔥 구조·컨벤션·역할 분리 등 어떤 부분이든 편하게 코멘트 주시면 감사하겠습니다 🙇♀️
📸 Screenshot
🔔 ETC