Skip to content
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

[Feat] 2차배포 (11/27) #297

Merged
merged 196 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
196 commits
Select commit Hold shift + click to select a range
60f1119
docs: readme 수정
simeunseo Nov 22, 2024
233de32
Merge pull request #245 from boostcampwm-2024/docs/#244/readme
simeunseo Nov 22, 2024
3edb84e
feat: dashboard api 네이밍 수정
simeunseo Nov 23, 2024
b6d1f41
feat: cookieparser 설치 및 적용
begong313 Nov 23, 2024
1e91054
Merge pull request #248 from boostcampwm-2024/feat/#247/cookie-parser
begong313 Nov 23, 2024
2f49e81
feat: 로그인 정보 없을떄 에러추가, 토큰인증실패시 에러추가
begong313 Nov 23, 2024
d3e147c
Merge pull request #250 from boostcampwm-2024/feat/#246/unauthorize-e…
begong313 Nov 23, 2024
016536b
feat: ticle list zod schema 정의
simeunseo Nov 23, 2024
d224714
feat: zod schema 검증을 위한 api request 유틸 함수 구현
simeunseo Nov 23, 2024
28b7f42
refactor: 불필요한 파일 삭제
begong313 Nov 23, 2024
a8f19d4
feat: 서버 연결 및 카드 컴포넌트 리스트 구현
simeunseo Nov 23, 2024
b767f30
feat: 카드 호버 스타일링 추가
simeunseo Nov 23, 2024
eb0fd52
feat: 배너 구현
simeunseo Nov 23, 2024
cd9b0c6
feat: Ticle Card에 디테일 페이지 링크 연결
simeunseo Nov 23, 2024
6927ff5
feat: Select를 통한 sort 구현
simeunseo Nov 23, 2024
1ec7e3c
feat: SearchInput 삽입
simeunseo Nov 23, 2024
54c7e68
feat: scroll restoration 적용
simeunseo Nov 23, 2024
5a03847
feat: CORS 옵션 제거
simeunseo Nov 23, 2024
5adaf97
feat: sort 캐싱이 안되어있을 때 리렌더링 되는 문제 해결
simeunseo Nov 23, 2024
18de0d8
feat: request 유틸 위치 변경
simeunseo Nov 23, 2024
f33f82b
feat: import 경로 수정
simeunseo Nov 23, 2024
e8b4653
feat: cors 옵션 제거
simeunseo Nov 23, 2024
33172a6
feat: SearchInput에 bg-white추가
simeunseo Nov 23, 2024
cb5d374
feat: SearchInput 크기 수정
simeunseo Nov 23, 2024
5fb60a7
feat: merge develop
simeunseo Nov 23, 2024
dab846d
feat: Merge branch 'feat/#7/ticle-list' into feat/#20/dashboard
simeunseo Nov 23, 2024
0d43ffe
feat: dashboard list 응답 schema 정의
simeunseo Nov 23, 2024
e349226
feat: dashboard list api 연결
simeunseo Nov 23, 2024
c0d1646
feat: dashboard 퍼블리싱
simeunseo Nov 23, 2024
2bc949a
feat: 티클 상세조회 응답 스키마 정의
simeunseo Nov 23, 2024
fe2771a
feat: 티클 상세조회 api 연결
simeunseo Nov 23, 2024
e34c18b
feat: 티클 신청 mutate 연결
simeunseo Nov 23, 2024
f704126
feat: 티클 생성 mutate 연결
simeunseo Nov 23, 2024
a0ba674
feat: 티클 생성시 발표자 이름 글자수 제한 7자로 변경
simeunseo Nov 23, 2024
efe418f
feat: dashboard 조회시 placeholderData 옵션 추가
simeunseo Nov 23, 2024
5bb2ee2
feat: 대시보드 UI 수정
simeunseo Nov 23, 2024
2ab2804
fix: date->datetime type으로 수정
simeunseo Nov 23, 2024
cb6a21c
feat: 신청자 목록 응답 데이터 스키마 정의
simeunseo Nov 23, 2024
a315c2c
feat: transform transition 속성 global.css에서 삭제
simeunseo Nov 23, 2024
468356b
feat: 신청자 목록 모달 구현
simeunseo Nov 23, 2024
98f2613
design: scrollbar 디자인 커스텀
simeunseo Nov 23, 2024
15b2fd8
fix: 모달 안닫히는 버그 수정
simeunseo Nov 23, 2024
e604c19
feat: 티클 신청시 대시보드로 이동
simeunseo Nov 23, 2024
ec2123b
feat: 티클 신청시 티클 목록 조회, 대시보드 조회, 신청자 목록 조회에 대해 invalidateQueries
simeunseo Nov 23, 2024
537ffaf
chore: lint 에러
simeunseo Nov 23, 2024
d51962a
chore: lint 에러
simeunseo Nov 23, 2024
8c1b8d2
fix: console 삭제
simeunseo Nov 23, 2024
f5f3461
feat: dbExceptionfilter적용
begong313 Nov 24, 2024
9085dd2
fix: applicant Count 수정
Fixtar Nov 24, 2024
f10a20c
fix: tags 중복 제거
Fixtar Nov 24, 2024
411766c
chore: a11y 관련 eslint 비활성화
seoko97 Nov 24, 2024
463dfa9
Merge pull request #256 from boostcampwm-2024/fix/#249/add-applicant-…
Fixtar Nov 24, 2024
d733586
feat: socket connect error 추가
seoko97 Nov 24, 2024
b47cfa5
refactor: socket을 context를 통해 관리하도록 변경
seoko97 Nov 24, 2024
a4c545e
feat: error message 타입 작성
Fixtar Nov 24, 2024
6b48882
Merge pull request #253 from boostcampwm-2024/feat/#7/ticle-list
simeunseo Nov 25, 2024
0def81d
Merge pull request #254 from boostcampwm-2024/feat/#20/dashboard
simeunseo Nov 25, 2024
55126b6
refactor: filter 도입으로 불필요해진 TRY-CATCH 제거
begong313 Nov 24, 2024
4f7857b
Merge pull request #255 from boostcampwm-2024/feat/#252/database-exce…
begong313 Nov 25, 2024
25f59fd
feat: join-room할때 nickname을 받아 저장
begong313 Nov 25, 2024
e9d16ef
feat: produce 이벤트 시 nickname 데이터 추가
begong313 Nov 25, 2024
412772a
feat: get-producers 요청에 nickname 추가
begong313 Nov 25, 2024
f4281cd
fix: 데이터 변경 후 producer의 정보 못가져오던 버그 수정 producer 내부 객체가 getter setter로…
begong313 Nov 25, 2024
b269be1
feat: Merge branch 'develop' into feat/#257/error-message
Fixtar Nov 25, 2024
13864ae
feat: error message로 변경
Fixtar Nov 25, 2024
25124b0
feat: 사용하지 않는 파일 제거
seoko97 Nov 25, 2024
c645c71
fix: 이미 존재하는 consumer를 생성하던 오류 수정
seoko97 Nov 25, 2024
f6b7f81
feat: 카메라, 마이크, 화면 스트림을 가져오는 유틸리티 함수 추가
seoko97 Nov 25, 2024
2bc987e
feat: live 페이지 context provider 추가
seoko97 Nov 25, 2024
63f4b47
feat: 원격 및 로컬 스트림을 위한 context 및 provider 추가
seoko97 Nov 25, 2024
00b210e
refactor: context api를 통한 props drilling 개선
seoko97 Nov 25, 2024
5426344
feat: unmount시 disconnect 함수 실행
seoko97 Nov 25, 2024
c8a8853
feat: if문 제거
seoko97 Nov 25, 2024
738f5bf
feat: 상대 경로를 절대 경로로 변경
seoko97 Nov 25, 2024
209c918
fix: socket을 중복해서 호출하던 오류 수정
seoko97 Nov 25, 2024
34a4f76
Merge pull request #271 from boostcampwm-2024/feat/#259/meetingroom-n…
begong313 Nov 25, 2024
2503baf
feat: 게스트로그인 클릭 시 유저 생성
begong313 Nov 25, 2024
3f5e4d0
feat: guestlogin 충돌방지
begong313 Nov 25, 2024
40aee23
feat: 미디어 서버 소켓 예외처리 필터 구현
Jieun1ee Nov 25, 2024
215686b
feat: throttler도입으로 guestlogin 분당 횟수 제한
begong313 Nov 25, 2024
fffe5be
feat: 필터 위치 수정
Jieun1ee Nov 25, 2024
815ff90
feat: Tab 공통 컴포넌트에서 value와 label을 분리하여 사용하도록 수정
simeunseo Nov 25, 2024
4d51092
feat: 변경된 Tab 공통 컴포넌트에 맞춰서 DashboardTab 사용 방식 변경
simeunseo Nov 25, 2024
d5e90bf
feat: Tab story 수정
simeunseo Nov 25, 2024
473f406
feat: 티클 리스트에서 진행예정/종료 탭 추가
simeunseo Nov 25, 2024
4d755be
fix: totalItemCount, isOpen 수정
Fixtar Nov 25, 2024
0fffa1d
fix: 묵시적 형변환 옵션 제거
Fixtar Nov 25, 2024
dbc3e4c
feat: Loading 컴포넌트 수정
simeunseo Nov 25, 2024
46d16e8
feat: Loading 컴포넌트 story 추가
simeunseo Nov 25, 2024
735c37a
feat: 티클 목록 조회시 기존 useQuery를 useInfiniteQuery로 변경
simeunseo Nov 25, 2024
8db1826
Merge pull request #272 from boostcampwm-2024/feat/#257/error-message
Fixtar Nov 25, 2024
d705e30
feat: 무한 스크롤 커스텀훅 구현
simeunseo Nov 25, 2024
9b6e32c
feat: 티클 리스트 조회시 무한스크롤과 로딩 인디케이터 추가
simeunseo Nov 25, 2024
888e6d8
feat: 기존 대시보드 조회 쿼리를 useInfiniteQuery로 변경
simeunseo Nov 25, 2024
b204788
design: 대시보드 카드에서 개설자 명이 길때 레이아웃이 깨지지 않도록 고정된 width 추가
simeunseo Nov 25, 2024
533a455
feat: 신청한 티클, 개설한 티클에 대해 10개씩 무한 스크롤 적용
simeunseo Nov 25, 2024
aafaba9
feat: 대시보드에서 티클 카드 클릭시 해당 티클 상세페이지로 이동
simeunseo Nov 25, 2024
2a841f3
feat: Link태그 내 Link태그가 중첩되는 문제 해결
simeunseo Nov 25, 2024
04c2fe3
feat: DashboardTab에서 state가 아닌 url에 따라서 tab을 전환하도록 변경
simeunseo Nov 25, 2024
e965652
feat: Header를 root에 조건부 렌더링하는 것이 아닌 필요한 곳에 직접 삽입하여 리렌더링 이슈 해결
simeunseo Nov 25, 2024
d003f97
feat: 메인 페이지에서 탭 전환에 따른 리렌더링 개선
simeunseo Nov 25, 2024
4b890d5
feat: 티클 리스트, 대시보드에 대해 Empty 뷰 추가
simeunseo Nov 25, 2024
b0eaf1b
feat: 티클 신청시 alert
simeunseo Nov 25, 2024
28071d1
feat: profileUrl 고양이로 변경
begong313 Nov 26, 2024
016d6a3
Merge branch 'develop' into fix/#277/fix-pagenation
Fixtar Nov 26, 2024
8a5c3ab
Merge pull request #278 from boostcampwm-2024/fix/#277/fix-pagenation
Fixtar Nov 26, 2024
b4561dc
feat: 티클 호스트 여부 추가
Fixtar Nov 26, 2024
53dd259
design: Empty 뷰에 점선 border 적용
simeunseo Nov 26, 2024
b54ae85
feat: 미디어 타입에 stream 상태를 저장하도로 변경
seoko97 Nov 26, 2024
b296763
feat: 화면 공유 직접 종료시 screen에 대한 state 정보를 제거하도록 변경
seoko97 Nov 26, 2024
beee810
fix: 병합 충돌 해결
seoko97 Nov 26, 2024
aee61c5
feat: 티클 참가신청 여부 추가
Fixtar Nov 26, 2024
fd62076
feat: 개설한 티클 목록에서 참여자 목록 모달 열 때 link 태그 동작 없애기
simeunseo Nov 26, 2024
2799faf
feat: 참여자 목록 모달에 Empty 뷰 추가
simeunseo Nov 26, 2024
8b41b4d
feat: 티클 목록조회시 발표자 이미지 추가
Fixtar Nov 26, 2024
e6f49ce
feat: 티클 생성시 대시보드 조회 invalidateQueries
simeunseo Nov 26, 2024
2e550e7
design: 태그의 최대 크기에 맞춰서 티클 카드 레이아웃 조정
simeunseo Nov 26, 2024
55c402f
Merge pull request #279 from boostcampwm-2024/feat/#30/pagination
simeunseo Nov 26, 2024
4bb6d11
feat: merge develop branch
begong313 Nov 26, 2024
1a544b6
Merge pull request #275 from boostcampwm-2024/feat/#267/guest-login
begong313 Nov 26, 2024
cc2dd09
feat: oauthlogin 유틸 수정
simeunseo Nov 26, 2024
cb66913
feat: OAuth 로그인 버튼 구현
simeunseo Nov 26, 2024
f1e77cb
feat: 로그인 페이지 구현
simeunseo Nov 26, 2024
5f77458
feat: 로그인 관련 asset 추가
simeunseo Nov 26, 2024
7954c1b
feat: merge develop
simeunseo Nov 26, 2024
c23365e
feat: video 세부 스타일 변경
seoko97 Nov 26, 2024
c4ae6c1
feat: children을 기준으로 좌우에 버튼이 생기도록 변경
seoko97 Nov 26, 2024
479a691
feat: 사용하지 않는 style 제거
seoko97 Nov 26, 2024
dd70c8c
feat: item이 3개 이상일 때 display grid로 변경
seoko97 Nov 26, 2024
0d2ff4f
fix: 병합 충돌 수정
seoko97 Nov 26, 2024
bb847cf
feat: guest login 구현
simeunseo Nov 26, 2024
0228f20
Merge pull request #273 from boostcampwm-2024/feat/#251/mediasoup-ref…
seoko97 Nov 26, 2024
0bad7f7
fix: 병합 충돌 해결
seoko97 Nov 26, 2024
dadfea0
Merge pull request #276 from boostcampwm-2024/feat/#258/socket-except…
Jieun1ee Nov 26, 2024
9dd006b
Merge pull request #284 from boostcampwm-2024/feat/#274/video-pagenation
seoko97 Nov 26, 2024
48de519
feat: 고양이 이미지 api 교체
simeunseo Nov 26, 2024
966b9ae
feat: Dialog 내부 클릭시 이벤트 전파 방지
simeunseo Nov 26, 2024
4dcbe1d
feat: 티클 리스트 Empty 뷰 렌더링 조건 변경
simeunseo Nov 26, 2024
4a38514
feat: oauth 로그인시 로딩 추가
simeunseo Nov 26, 2024
c682390
feat: userInfoDto 생성
simeunseo Nov 26, 2024
f28dbc8
feat: user 프로필 조회 api 구현
simeunseo Nov 26, 2024
5e35234
feat: userInfoDto 삭제
simeunseo Nov 26, 2024
b368592
feat: 네이밍 변경
simeunseo Nov 26, 2024
cfc00a9
feat: 경로 수정
simeunseo Nov 26, 2024
ed0b9eb
feat: user id로 유저 정보 조회 API 구현
simeunseo Nov 26, 2024
3555752
feat: 티클 상세 조회 API 응답에 speakerId 추가
simeunseo Nov 26, 2024
d8fb59d
feat: favicon 업데이트
simeunseo Nov 26, 2024
e36f6a4
Merge pull request #282 from boostcampwm-2024/feat/#281/api-add-fields
Fixtar Nov 26, 2024
357591a
feat: Provider 타입 안정성 강화 및 공통 타입으로 분리
simeunseo Nov 26, 2024
a95b1c5
feat: provider 타입 적용
simeunseo Nov 26, 2024
b9c8d0e
feat: user 관련 api 훅 구현
simeunseo Nov 26, 2024
592649d
feat: Header 내 유저 정보 UI 구현
simeunseo Nov 26, 2024
e43f5ff
feat: Avatar story 수정
simeunseo Nov 26, 2024
0b41c5d
feat: 인증 여부에 따른 헤더 내 로그인 버튼 분기 처리 임시 구현
simeunseo Nov 26, 2024
f61be31
feat: 내 프로필 모달 구현
simeunseo Nov 26, 2024
b6f5dcb
refactor: 컴포넌트 분리
simeunseo Nov 26, 2024
ce97d3c
fix: Select 스토리 에러 해결
simeunseo Nov 26, 2024
49154e2
feat: logout 기능 추가
begong313 Nov 26, 2024
b176fde
feat: 유저 정보 조회 API에서 티클 제목과 함께 ticleId도 포함하여 응답
simeunseo Nov 26, 2024
300c5b6
feat: 발표자 프로필 클릭시 유저 정보 다이얼로그 구현
simeunseo Nov 26, 2024
911369d
feat: 티클 상세 페이지에서 프로필 이미지 보여주기
simeunseo Nov 26, 2024
71c8786
feat: 티클 전체 목록에서 프로필 이미지 노출
simeunseo Nov 26, 2024
31c5f29
feat: merge develop
simeunseo Nov 26, 2024
0f907d7
feat: 티클 전체 목록 조회에서 프로필 이미지 가져오는 방식 수정
simeunseo Nov 26, 2024
b608acd
feat: lint 에러 해결
simeunseo Nov 26, 2024
41bc5e0
feat: 기존 파일 제거
seoko97 Nov 26, 2024
83a49a1
feat: 기존 파일 분리 및 view 최적화
seoko97 Nov 26, 2024
68f5cc4
feat: pagination button position을 relative로 변경
seoko97 Nov 26, 2024
3c62dd8
feat: close screen 함수 추가
seoko97 Nov 26, 2024
705e4ca
feat: StreamData 인터페이스 제거
seoko97 Nov 26, 2024
474fcd6
feat: StreamView 컴포넌트 리팩토링 및 핀된 비디오 기능 개선
seoko97 Nov 26, 2024
cf72b98
feat: 로컬 스트림 관리 개선 및 화면 스트림 종료 함수 추가
seoko97 Nov 26, 2024
4f7b3b5
feat: Mediasoup 훅에서 로컬 및 원격 스트림 설정 함수 분리
seoko97 Nov 26, 2024
48398ef
feat: useAudioState 훅 추가 및 오디오 음소거 상태 가져오기 기능 구현
seoko97 Nov 26, 2024
9f8811c
feat: hook 내부에서 stream 정보를 저장하도록 수정
seoko97 Nov 26, 2024
8f6a69e
feat: 비디오 스트림 핀 기능 custom hook으로 분리
seoko97 Nov 26, 2024
4961fb4
style: import 순서 수정
seoko97 Nov 26, 2024
e719db7
feat: setTimeout 제거
seoko97 Nov 26, 2024
236a73b
Merge pull request #291 from boostcampwm-2024/feat/#290/logout
begong313 Nov 26, 2024
2afd5ad
feat: 현재 페이지가 0 이하일 때 페이지 설정 방지
seoko97 Nov 27, 2024
42309b2
feat: merge develop
simeunseo Nov 27, 2024
0824d68
feat: logout 연동
simeunseo Nov 27, 2024
a753bc2
Merge pull request #286 from boostcampwm-2024/feat/#283/oauth
simeunseo Nov 27, 2024
7bd2bd6
feat: 사용하지 않는 import 제거
simeunseo Nov 27, 2024
c48f2c6
Merge pull request #288 from boostcampwm-2024/feat/#52/user
simeunseo Nov 27, 2024
8e76384
Merge branch 'develop' into feat/#37/profile
simeunseo Nov 27, 2024
5faebdd
chore: 포맷팅 문제 해결
simeunseo Nov 27, 2024
1f04bdc
feat: 오타 수정
seoko97 Nov 27, 2024
7024318
chore: 포맷팅 문제 해결
simeunseo Nov 27, 2024
811628a
Merge pull request #294 from boostcampwm-2024/feat/#37/profile
simeunseo Nov 27, 2024
926c8bf
feat: 파일 명을 더 직관적으로 변경
seoko97 Nov 27, 2024
cab0f0b
fix: 병합 충돌 해결
seoko97 Nov 27, 2024
4945b91
Merge pull request #295 from boostcampwm-2024/feat/#274/video-pagenation
seoko97 Nov 27, 2024
2f378c1
feat: SVG 변경에 따른 기본 style 수정
seoko97 Nov 27, 2024
e76fd04
feat: cors 설정 추가
seoko97 Nov 27, 2024
83643f4
Merge pull request #296 from boostcampwm-2024/feat/#274/video-pagenation
seoko97 Nov 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,21 @@
<img width="600" alt="메인 배너" src="https://github.com/user-attachments/assets/eb4c89c8-6870-4114-bddc-796b51bd7163">
<br/>

### [:ledger: 팀 노션](https://www.notion.so/simeunseo/9-Ticle-12e599a6f0d2804682ccd2251248a435?pvs=4) | [:mag: 위키](https://github.com/boostcampwm-2024/web21-boostproject/wiki) | [🎨 피그마](https://www.figma.com/design/nw74detTvjXGrDP2cfdmwp/TICLE-%EB%94%94%EC%9E%90%EC%9D%B8?node-id=32-4477&t=3FCCnBpgQXMZs63X-1) | [🗓️ 스프린트 백로그](https://github.com/orgs/boostcampwm-2024/projects/82/views/7)
### [:ledger: 팀 노션](https://www.notion.so/simeunseo/9-Ticle-12e599a6f0d2804682ccd2251248a435?pvs=4) | [:mag: 위키](https://github.com/boostcampwm-2024/web21-boostproject/wiki) | [🎨 피그마](https://www.figma.com/design/nw74detTvjXGrDP2cfdmwp/TICLE-%EB%94%94%EC%9E%90%EC%9D%B8?node-id=32-4477&t=3FCCnBpgQXMZs63X-1) | [🗓️ 스프린트 백로그](https://github.com/orgs/boostcampwm-2024/projects/82/views/7) | [🧪 스토리북](https://673a0cccd15a760db778c591-kxdpixadfg.chromatic.com/?path=/docs/common-dialog--docs)

</div>

# 🖧 시스템 아키텍처

<img width="6176" alt="아키텍처" src="https://github.com/user-attachments/assets/dc0a4690-e906-4068-b391-f15f6fcdc9a6">

# 🏃 작업 진행 상황

- [🆕 4주차 발표자료](https://simeunseo.notion.site/4-1ccf63bab4b14fd8b249f5d7c7cd7e53?pvs=4)
- [3주차 발표자료](https://simeunseo.notion.site/3-0df689ca7cd3407b89a93284854a54b8?pvs=4)
- [2주차 발표자료](https://simeunseo.notion.site/2-137599a6f0d2809fa498fa1cc31d97f9?pvs=4)
- [1주차 발표자료](https://simeunseo.notion.site/1-130599a6f0d2804597e0c55e8ee33920?pvs=4)

# 💡 핵심 기능

### **✔️ 실시간 화상 지식 공유**
Expand Down Expand Up @@ -40,16 +51,6 @@

CLOVA API를 이용해 티클 내용을 요약하여 제공합니다.

# 📽️ 스트리밍 구현 흐름

### Producer(미디어 전송 엔드포인트)

<img width="2768" alt="mediasoup sequence diagram - producer" src="https://github.com/user-attachments/assets/8b10a0be-c0c4-4e41-b3a9-462b5fc78be6">

### Consumer(미디어 수신 엔드포인트)

<img width="2768" alt="mediasoup sequence diagram - consumer" src="https://github.com/user-attachments/assets/fd5d2819-bc96-4598-9875-18cb67abb20d">

# ✍️ 학습 정리

| 분야 | 기술 |
Expand Down
9 changes: 7 additions & 2 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"license": "UNLICENSED",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
"format": "prettier --write \"src/**/*.ts\" ",
"format:check": "prettier --check \"src/**/*.ts\" ",
"start": "nest start",
"dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
Expand All @@ -29,9 +29,13 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/swagger": "^8.0.1",
"@nestjs/throttler": "^6.2.1",
"@nestjs/typeorm": "^10.0.2",
"@repo/types": "workspace:*",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cookie-parser": "^1.4.7",
"eslint-import-resolver-typescript": "^3.6.3",
"jsonwebtoken": "^9.0.2",
"mysql2": "^3.11.3",
Expand All @@ -52,6 +56,7 @@
"@repo/lint": "workspace:*",
"@repo/tsconfig": "workspace:*",
"@types/bcrypt": "^5.0.2",
"@types/cookie-parser": "^1.4.7",
"@types/express": "^5.0.0",
"@types/jest": "^29.5.2",
"@types/jsonwebtoken": "^9.0.7",
Expand Down
7 changes: 7 additions & 0 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ThrottlerModule } from '@nestjs/throttler';
import { TypeOrmModule } from '@nestjs/typeorm';

import { TypeOrmConfigService } from '@/config/typeorm.config';
Expand All @@ -16,6 +17,12 @@ import { UserModule } from './user/user.module';
isGlobal: true,
envFilePath: '.env',
}),
ThrottlerModule.forRoot([
{
ttl: 60000,
limit: 100,
},
]),
AuthModule,
TicleModule,
StreamModule,
Expand Down
59 changes: 37 additions & 22 deletions apps/api/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Body, Controller, Get, Post, Res, UseGuards } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { ThrottlerGuard } from '@nestjs/throttler';
import { Response } from 'express';

import { GetUserId } from '@/common/decorator/get-userId.decorator';
import { CookieConfig } from '@/config/cookie.config';

import { AuthService } from './auth.service';
import { LocalLoginRequestDto } from './dto/localLoginRequest.dto';
Expand All @@ -16,13 +18,18 @@ import { LocalAuthGuard } from './local/local-auth.guard';
@Controller('auth')
@ApiTags('Auth')
export class AuthController {
private readonly redirectUrl: string;

constructor(
private authService: AuthService,
private configService: ConfigService
) {}
private readonly authService: AuthService,
private readonly configService: ConfigService,
private readonly cookieConfig: CookieConfig
) {
this.redirectUrl = this.configService.get<string>('LOGIN_REDIRECT_URL');
}

@Post('signup')
@ApiOperation({ summary: '회원가입' })
@ApiOperation({ summary: '로컬 회원가입' })
@ApiResponse({ status: 201, type: SignupResponseDto })
@ApiResponse({ status: 409 })
async signup(@Body() createUserDto: LocalSignupRequestDto): Promise<SignupResponseDto> {
Expand All @@ -37,7 +44,16 @@ export class AuthController {
@ApiResponse({ status: 401 })
@UseGuards(LocalAuthGuard)
localLogin(@GetUserId() userId: number, @Res() response: Response) {
this.cookieInsertJWT(response, userId);
this.loginProcess(response, userId);
}

@Get('guest/login')
@ApiOperation({ summary: '게스트 로그인' })
@ApiResponse({ status: 302, description: '홈으로 리다이렉션' })
@UseGuards(ThrottlerGuard)
async guestLogin(@Res() response: Response) {
const guestUser = await this.authService.createGuestUser();
this.loginProcess(response, guestUser.id);
}

@Get('google/login')
Expand All @@ -50,7 +66,7 @@ export class AuthController {
@Get('google/callback')
@UseGuards(GoogleAuthGuard)
googleAuthCallback(@GetUserId() userId: number, @Res() response: Response) {
this.cookieInsertJWT(response, userId);
this.loginProcess(response, userId);
}

@Get('github/login')
Expand All @@ -63,25 +79,24 @@ export class AuthController {
@Get('github/callback')
@UseGuards(GitHubAuthGuard)
githubAuthCallback(@GetUserId() userId: number, @Res() response: Response) {
this.cookieInsertJWT(response, userId);
this.loginProcess(response, userId);
}

private setAuthCookie(response: Response, accessToken: string) {
response.cookie('accessToken', accessToken, {
httpOnly: true,
secure: this.configService.get<string>('NODE_ENV') === 'production',
sameSite: 'lax',
path: '/',
});
@Get('logout')
@ApiOperation({ summary: '로그아웃' })
@ApiResponse({ status: 302, description: '홈으로 리다이렉션' })
logout(@Res() response: Response) {
response.clearCookie('accessToken', this.cookieConfig.getAuthCookieOptions());
this.redirectToHome(response);
}

private async cookieInsertJWT(
response: Response,
userId: number,
redirectUrl: string = this.configService.get<string>('LOGIN_REDIRECT_URL')
) {
const { accessToken } = await this.authService.createJWT(userId);
this.setAuthCookie(response, accessToken);
response.redirect(redirectUrl);
private loginProcess(response: Response, userId: number) {
const { accessToken } = this.authService.createJWT(userId);
response.cookie('accessToken', accessToken, this.cookieConfig.getAuthCookieOptions());
this.redirectToHome(response);
}

private redirectToHome(response: Response) {
response.redirect(this.redirectUrl);
}
}
10 changes: 9 additions & 1 deletion apps/api/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';

import { CookieConfig } from '@/config/cookie.config';
import { UserModule } from '@/user/user.module';

import { AuthController } from './auth.controller';
Expand All @@ -27,6 +28,13 @@ import { LocalStrategy } from './local/local.strategy';
}),
],
controllers: [AuthController],
providers: [AuthService, LocalStrategy, JwtStrategy, GitHubStrategy, GoogleStrategy],
providers: [
AuthService,
LocalStrategy,
JwtStrategy,
GitHubStrategy,
GoogleStrategy,
CookieConfig,
],
})
export class AuthModule {}
11 changes: 2 additions & 9 deletions apps/api/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jest.mock('bcrypt', () => ({

describe('AuthService', () => {
let service: AuthService;
let userService: UserService;

let jwtService: JwtService;

// Mock UserService
Expand Down Expand Up @@ -49,7 +49,7 @@ describe('AuthService', () => {
}).compile();

service = module.get<AuthService>(AuthService);
userService = module.get<UserService>(UserService);

jwtService = module.get<JwtService>(JwtService);

// Clear all mocks before each test
Expand All @@ -63,13 +63,6 @@ describe('AuthService', () => {
password: 'password123',
};

const mockUser = {
id: 1,
username: 'testuser',
password: 'hashedPassword',
email: '[email protected]',
};

it('should throw UnauthorizedException if user is not found', async () => {
mockUserService.findUserByUsername.mockResolvedValue(null);

Expand Down
34 changes: 25 additions & 9 deletions apps/api/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';
import { Provider } from '@repo/types';

import { CreateSocialUserDto } from '@/user/dto/createSocialUser.dto';
import { UserService } from '@/user/user.service';
Expand All @@ -15,11 +16,7 @@ export class AuthService {
) {}

async signupLocal(signupRequestDto: LocalSignupRequestDto) {
const existingUser = await this.userService.findUserByUsername(signupRequestDto.username);
if (existingUser) {
throw new BadRequestException('이미 사용 중인 사용자 이름입니다.');
}
return this.userService.createLocalUser({ provider: 'local', ...signupRequestDto });
return this.userService.createLocalUser({ provider: Provider.local, ...signupRequestDto });
}

async validateLocalLogin(username: string, inputPassword: string) {
Expand All @@ -31,8 +28,27 @@ export class AuthService {
if (!isPasswordValid) {
throw new UnauthorizedException('잘못된 로그인 정보');
}
const { password, ...result } = user;
return result;
return user;
}

async createGuestUser() {
const randomNum = Math.floor(Math.random() * 10000);
const response = await fetch('https://api.thecatapi.com/v1/images/search');
const catImageUrl = (await response.json())[0].url;

const guestUser = {
username: `guest_${randomNum}`,
password: `guest_password_${randomNum}`,
email: `[email protected]`,
nickname: `guest_${randomNum}`,
introduce: `게스트 사용자입니다. `,
profileImageUrl: catImageUrl,
};
const user = await this.userService.findUserByUsername(guestUser.username);
if (!user) {
return this.userService.createLocalUser({ provider: Provider.guest, ...guestUser });
}
return user;
}

async checkSocialUser(socialUserData: CreateSocialUserDto) {
Expand All @@ -46,7 +62,7 @@ export class AuthService {
return user;
}

async createJWT(userId: number) {
createJWT(userId: number) {
const payload = { sub: userId };
return {
accessToken: this.jwtService.sign(payload),
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/auth/github/github.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy } from 'passport-github2';
import { Provider } from '@repo/types';

import { AuthService } from '../auth.service';

@Injectable()
export class GitHubStrategy extends PassportStrategy(Strategy, 'github') {
export class GitHubStrategy extends PassportStrategy(Strategy, Provider.github) {
constructor(
private configService: ConfigService,
private authService: AuthService
Expand All @@ -23,7 +24,7 @@ export class GitHubStrategy extends PassportStrategy(Strategy, 'github') {
const { id, username, emails, photos } = profile;

const user = {
provider: 'github',
provider: Provider.github,
socialId: id,
nickname: username,
email: emails[0].value,
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/auth/google/google.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy } from 'passport-google-oauth20';
import { Provider } from '@repo/types';

import { AuthService } from '../auth.service';

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
export class GoogleStrategy extends PassportStrategy(Strategy, Provider.google) {
constructor(
private configService: ConfigService,
private authService: AuthService
Expand All @@ -23,7 +24,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
const { id, displayName, emails, photos } = profile;

const user = {
provider: 'google',
provider: Provider.google,
socialId: id,
nickname: displayName,
email: emails[0].value,
Expand Down
17 changes: 13 additions & 4 deletions apps/api/src/auth/jwt/jwt-auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ErrorMessage } from '@repo/types';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
getRequest(context: ExecutionContext) {
const req = context.switchToHttp().getRequest();

const cookies = req.cookies;

const token = cookies['accessToken'];

if (token) req.headers.authorization = `Bearer ${token}`;
if (!token) {
throw new UnauthorizedException(ErrorMessage.LOGIN_REQUIRED);
}
req.headers.authorization = `Bearer ${token}`;

return req;
}

handleRequest(err: any, user: any) {
if (err || !user) {
throw new UnauthorizedException(ErrorMessage.INVALID_AUTHENTICATION_INFORMATION);
}
return user;
}
}
Loading