⚽ 구단주주총회
🖥️ 프로젝트 소개
온라인 게임인 FC ONLINE의 API를 활용하여 게임 내 사용자의 전적을 확인하고 유저들과 소통할 수 있는 전적 & 커뮤니티
- 게임 내 전적을 그래프를 통해 수치화 하여 보여줄 수 있으며,
기존 다른 FC Online의 전적 검색 사이트와는 다르게 커뮤니티의 기능을 추가한 프로젝트 입니다.
🔗 배포 링크
구단 주주 총회 배포 링크
👨👩👧👦 팀 소개
🕰️ 개발 기간
총 개발 기간 : 24.10.10 ~ 24.10.16
프로젝트 기획 : 24.10.10 ~ 24.10.10
프로젝트 기본 세팅 : 24.10.11~24.10.11
기능 구현 완료 : 24.10.11 ~ 24.10.15
추가 구현 완료 : 24.10.15 ~ 24.10.16
📊 기술적 의사 결정
| 요구사항 | 선택지 | 사용 근거 |
|---|
| 전역상태 라이브러리 | zustand | 과도한 props 사용을 방지하고 가벼운 전역 state 관리를 위해 zustand 사용 |
| 서버상태 라이브러리 | tanstack-query | 서버상태 관리를 쉽게 해주고 복잡한 비동기 로직을 단순화 하기 위해 사용 |
| 백엔드 서비스 | Supabase | 로그인 및 회원가입 서비스를 도와주는 백엔드 서비스와 게시물 관리를 위해 DB를 사용 |
| 글 작성 Tool | TOAST UI Editor | 글 작성 시 편의성을 극대화 하기 위해 TOAST UI Editor 사용 |
| UI 통일성 | Shadcn | 전적 검색 시 Accordion이나 버튼, input등의 UI의 통일성/편의성을 위해 사용 |
📂 폴더 구조
폴더구조
📦9danjuju
┣ 📂public
┃ ┗ 📂img
┃ ┃ ┣ 📜anonPlayerImage.png
┃ ┃ ┣ 📜favicon.png
┃ ┃ ┣ 📜field_img.jpg
┃ ┃ ┗ 📜homeBackgroundImage.jpg
┣ 📂src
┃ ┣ 📂app
┃ ┃ ┣ 📂api
┃ ┃ ┃ ┣ 📂@modal
┃ ┃ ┃ ┃ ┗ 📂(...)detail
┃ ┃ ┃ ┃ ┃ ┗ 📂[nickname]
┃ ┃ ┃ ┣ 📂matchDetail
┃ ┃ ┃ ┃ ┗ 📜route.ts
┃ ┃ ┃ ┣ 📂matchId
┃ ┃ ┃ ┃ ┗ 📜route.ts
┃ ┃ ┃ ┣ 📂playerdata
┃ ┃ ┃ ┃ ┗ 📂detail
┃ ┃ ┃ ┃ ┃ ┗ 📜route.ts
┃ ┃ ┃ ┣ 📂playerposition
┃ ┃ ┃ ┃ ┗ 📂detail
┃ ┃ ┃ ┃ ┃ ┗ 📜route.ts
┃ ┃ ┃ ┣ 📂user
┃ ┃ ┃ ┃ ┗ 📂detail
┃ ┃ ┃ ┃ ┃ ┗ 📜route.ts
┃ ┃ ┃ ┗ 📂usermatch
┃ ┃ ┃ ┃ ┗ 📂detail
┃ ┃ ┃ ┃ ┃ ┗ 📜route.ts
┃ ┃ ┣ 📂community
┃ ┃ ┃ ┣ 📂write
┃ ┃ ┃ ┃ ┗ 📜page.tsx
┃ ┃ ┃ ┣ 📂[id]
┃ ┃ ┃ ┃ ┣ 📂modify
┃ ┃ ┃ ┃ ┃ ┗ 📜page.tsx
┃ ┃ ┃ ┃ ┗ 📜page.tsx
┃ ┃ ┃ ┣ 📜loading.tsx
┃ ┃ ┃ ┗ 📜page.tsx
┃ ┃ ┣ 📂detail
┃ ┃ ┃ ┗ 📂[nickname]
┃ ┃ ┃ ┃ ┗ 📜page.tsx
┃ ┃ ┣ 📂fonts
┃ ┃ ┃ ┣ 📜NEXON-Football-Gothic-B.otf
┃ ┃ ┃ ┗ 📜NEXON-Football-Gothic-L.otf
┃ ┃ ┣ 📂login
┃ ┃ ┃ ┣ 📜loading.tsx
┃ ┃ ┃ ┗ 📜page.tsx
┃ ┃ ┣ 📂modal
┃ ┃ ┣ 📂mypage
┃ ┃ ┃ ┣ 📜loading.tsx
┃ ┃ ┃ ┗ 📜page.tsx
┃ ┃ ┣ 📂signup
┃ ┃ ┃ ┣ 📜loading.tsx
┃ ┃ ┃ ┗ 📜page.tsx
┃ ┃ ┣ 📜error.tsx
┃ ┃ ┣ 📜globals.css
┃ ┃ ┣ 📜layout.tsx
┃ ┃ ┗ 📜page.tsx
┃ ┣ 📂components
┃ ┃ ┣ 📂auth
┃ ┃ ┃ ┗ 📜AuthForm.tsx
┃ ┃ ┣ 📂comments
┃ ┃ ┃ ┗ 📜Comment.tsx
┃ ┃ ┣ 📂community
┃ ┃ ┃ ┣ 📜CommunityActionButton.tsx
┃ ┃ ┃ ┣ 📜CommunityList.tsx
┃ ┃ ┃ ┣ 📜HomeCommunityList.tsx
┃ ┃ ┃ ┗ 📜PostEditor.tsx
┃ ┃ ┣ 📂detail
┃ ┃ ┃ ┣ 📜DetailGraph.tsx
┃ ┃ ┃ ┣ 📜MatchAccordion.tsx
┃ ┃ ┃ ┣ 📜MatchContainer.tsx
┃ ┃ ┃ ┣ 📜MatchDetailContents.tsx
┃ ┃ ┃ ┣ 📜MatchRateDetail.tsx
┃ ┃ ┃ ┣ 📜PlayerImage.tsx
┃ ┃ ┃ ┗ 📜UserInfoBox.tsx
┃ ┃ ┣ 📂Field
┃ ┃ ┃ ┗ 📜Field.tsx
┃ ┃ ┣ 📂layout
┃ ┃ ┃ ┗ 📜Header.tsx
┃ ┃ ┣ 📂mypage
┃ ┃ ┃ ┣ 📜MyInfo.tsx
┃ ┃ ┃ ┣ 📜MyPostsList.tsx
┃ ┃ ┃ ┣ 📜Nickname.tsx
┃ ┃ ┃ ┣ 📜Post.tsx
┃ ┃ ┃ ┣ 📜PostsTable.tsx
┃ ┃ ┃ ┗ 📜Selected.tsx
┃ ┃ ┣ 📂ui
┃ ┃ ┃ ┣ 📜accordion.tsx
┃ ┃ ┃ ┣ 📜button.tsx
┃ ┃ ┃ ┗ 📜input.tsx
┃ ┃ ┣ 📜LoadingSpinner.tsx
┃ ┃ ┗ 📜SearchBar.tsx
┃ ┣ 📂hooks
┃ ┃ ┣ 📜useGetMatchIdQuery.ts
┃ ┃ ┣ 📜useGetPlayersNameQuery.ts
┃ ┃ ┣ 📜useGetPositionQuery.ts
┃ ┃ ┗ 📜useMatchDetailDataQuery.ts
┃ ┣ 📂lib
┃ ┃ ┗ 📜utils.ts
┃ ┣ 📂provider
┃ ┃ ┗ 📜QueryProvider.tsx
┃ ┣ 📂types
┃ ┃ ┣ 📂detail
┃ ┃ ┣ 📜matchType.ts
┃ ┃ ┣ 📜maxDivisionType.ts
┃ ┃ ┗ 📜userInfoType.ts
┃ ┣ 📂utils
┃ ┃ ┣ 📂detail
┃ ┃ ┃ ┗ 📜datailApi.ts
┃ ┃ ┣ 📂mypage
┃ ┃ ┃ ┣ 📜api.ts
┃ ┃ ┃ ┗ 📜type.ts
┃ ┃ ┣ 📂services
┃ ┃ ┃ ┣ 📜matchDetailDataConverter.ts
┃ ┃ ┃ ┗ 📜utcTimeToKstConverter.ts
┃ ┃ ┣ 📂supabase
┃ ┃ ┃ ┣ 📜client.ts
┃ ┃ ┃ ┣ 📜middleware.ts
┃ ┃ ┃ ┗ 📜server.ts
┃ ┃ ┣ 📜client-action.ts
┃ ┃ ┗ 📜server-action.ts
┃ ┣ 📜middleware.ts
┃ ┗ 📜userStore.ts
┣ 📜.env.local
┣ 📜.eslintrc.json
┣ 📜.gitignore
┣ 📜.prettierrc
┣ 📜components.json
┣ 📜database.types.ts
┣ 📜next-env.d.ts
┣ 📜next.config.mjs
┣ 📜package.json
┣ 📜postcss.config.mjs
┣ 📜pull_request_template.md
┣ 📜README.md
┣ 📜tailwind.config.ts
┣ 📜tsconfig.json
┗ 📜yarn.lock
🧩 주요 기능

1. 회원 가입 및 로그인
SUPABASE를 사용하여 회원가입과 로그인을 구현 후
ZUSTAND를 사용해 로그인 여부를 전역상태로 관리합니다.
1-1. 회원가입

1-2. 로그인


2. 검색

3. 전적 확인


3-1-1. 유저 정보

- 검색한 유저의 정보와 전적을 확인할 수 있습니다.
3-2-1. 매치 타입


- 매치 타입에 맞는 전적을 확인할 수 있습니다.
3-3-1. 평점


- 특정 매치에 따른 선수 정보가 화면에 랜더링 되며, 클릭 시 모달로 선수 정보를 확인할 수 있습니다.

3-3-2. 슈팅

- 특정 매치의 슈팅 정보를 그래프로 확인할 수 있습니다.
3-3-3. 패스

- 특정 매치의 패스 정보를 그래프로 확인할 수 있습니다.
3-3-4. 수비

- 특정 매치의 수비 정보를 그래프로 확인할 수 있습니다.
4. 커뮤니티
4-1. 게시글 확인


- 무한 스크롤을 통해 페이지 이동 없이 전체 게시물을 확인할 수 있습니다.

4-2. 게시글 CRUD

TOAST UI EDITOR를 사용하여 글쓰기를 할 수 있습니다.



5. 댓글



6. 마이페이지

- 가입 시 입력한 닉네임이
NEXON OPEN API서버에 존재할 경우 해당 유저의 정보를 받아옵니다.
- 로그인 후 작성한 게시물을 확인할 수 있습니다.
🚨 트러블 슈팅
1. 랜더링 오류
1-1. 더보기 버튼 클릭 시 로딩 UI가 보이며 페이지가 깜빡 거리는 현상이 발생
- 기존 :
loading.tsx를 통해 loading 상태일 때 loading UI를 보여줘야 함
1-2. 해결 방법

해결 : 한 페이지에서 관리하던 loading.tsx를 Suspense를 통해 로딩 UI를 보여줘야 하는 곳을 세분화,
전적 검색페이지는 예외로 useInfiniteQuery의 isLoading을 통해 로딩 UI를 넣어주어 매치타입이 변할 때만 로딩 UI가 보이도록 수정
2. TOAST UI Editor 오류
2-1. PostEditor 최상단에 "use client"를 선언하고 Write 페이지로 이동할 시 ReferenceError: navigator is not defined 에러가 발생
기존 : TOAST UI Editor Form이 나타나야 한다.
- app/community/write/page.tsx - CommunityWritepage (서버 컴포넌트)
components/community/PostEditor.tsx - (클라이언트 컴포넌트)
CommunityWritePage 컴포넌트안에 PostEditor 컴포넌트가 있고 PostEditor에서
Toast ui Editor 라이브러리를 사용하려고 하는 구조이다.
2-2. 해결 방법

해결 : dynamic 함수를 사용해서 컴포넌트를 ssr에서 제외 시켜 서버사이드에서 빌드를 무시하게 하였다. const PostEditor = dynamic(() => import('@/components/community/PostEditor'), { ssr: false });
자체 평가 의견
| 이름 | 점수 | 피드백 |
|---|
| 권다정 | 8/10 | 팀프로젝트 하면서 CRUD를 온전히 맡아본 적이 없었는데 이번에 맡을 수 있어서 좋았고, 제가 두려워했던 것 중 하나인 zustand도 직접 사용해볼 수 있어서 대체적으로 만족스럽습니다. |
| 신한별 | 7/10 | 좀 더 깔끔한 코드를 작성하고 싶었는데 그러지 못했고, 아직 Next.js에 대한 이해도가 부족해서 장점을 활용하지 못한 것 같아 아쉽습니다! (ex. 모달을 parallel routes & Intercepting Routes로 구현). 하지만 생각했던 것들은 구현해서 만족스럽습니다. |
| 이기성 | 8/10 | Next.js의 렌더링 기법을 더 다양하게 사용해보고 싶었는데 그러지 못해서 아쉬운 점이 살짝 남았습니다. |
| 이석원 | 7/10 | 구상했던 기능들을 모두 구현했다는 점에서 많이 만족스럽지만, 서벅액션과 라우팅 핸들러에 대한 이해와 경험이 부족해서 아쉬움이 남는 것 같습니다. |
| 정지형 | 5/10 | "일단" 기능이 되긴 하기에 50점을 주었고, 코드 간결화가 안되어 있으며 API 함수도 제대로 관리하지 못하고 있습니다. |