본문 바로가기
Project/PORTFOLIO

[Portfolio] 국비지원 교육 과정으로 프로그래밍 수업을 듣는 학생들을 위한 커뮤니티 TOOK-PEAK

by 임성장 2023. 10. 14.
728x90

🖥️ 프로젝트 소개


TOOK-PEAK 구동화면

 

  • 국비지원 교육을 듣는 학생들이 다른 교육기관의 학생들과 교류를 통해 다양한 정보를 얻을 수 있도록 커뮤니티 사이트를 제작하였습니다.
  • 취업, 아이디어, 기술 등 양질의 정보를 서로 공유하고, 같은 뜻을 가지고 있는 사람과 함께 협업을 할 수 있으며, 선의의 비교를 통해 개발자에 대한 동기부여를 얻을 수 있도록 프로젝트를 만들었습니다.
  • 이 프로젝트를 통해 학생들이 정보를 공유하고 협업을 통해 성장할 수 있도록 하였습니다.

 

🕰️ 개발 기간


  • 23.08.19 - 23.09.06 (19일)

 

⚙️ 개발 환경


  • Next.js 13.2.4
  • React 18.2.0
  • SCSS 1.66.1
  • IDE : VScode 1.80
  • ETC : Github / Window, Mac OS 환경에서 개발
  • DEPLOY : vercel

 

💾 Package


  • @next-auth/mongodb-adapter: 인증 및 세션 관리를 위한 MongoDB 어댑터.
  • aws-sdk(2.1440.0): Amazon Web Services (AWS)와 상호 작용하기 위한 SDK.
  • bcrypt(5.1.1): 암호화 및 해시 기능을 제공하는 패키지.
  • mongodb(5.8.0): MongoDB 데이터베이스와 상호 작용하기 위한 드라이버.
  • next-auth(4.23.1): 인증 및 세션 관리를 위한 패키지.
  • react-bootstrap(2.8.0): 부트스트랩과 리액트를 통합하는 패키지.
  • react-datepicker(4.16.0): 날짜 선택을 위한 리액트 컴포넌트.
  • react-icons(4.10.1): 아이콘 라이브러리.
  • react-js-pagination(3.0.3): 페이지네이션을 위한 리액트 컴포넌트.
  • zustand(4.4.1): 상태 관리 라이브러리

 

📁 폴더 구조


TOOK-PEAK 폴더 구조

📂 .next

  • 빌드 및 번들링과 관련된 파일 및 폴더가 여기에 생성됩니다. 
  • 이 폴더는 빌드 프로세스와 런타임에서 사용되는 중요한 폴더입니다.

📂 app

  • Next.js 앱의 페이지 컴포넌트가 저장되는 곳입니다. 
  • 폴더 이름에 따라 라우팅이 자동으로 설정되고 page.js, layout.js 파일로 페이지 파일을 생성합니다.

📂 components

  • 재사용 가능한 React 컴포넌트를 저장하는 폴더입니다.
  • 페이지와 기능에 따라 분류하여 누구나 보기 쉽도록 정리하였습니다.

📂 pages

  • 서버 기능을 수행하는 파일들로, API들을 모아놓은 폴더입니다.

📂 public

  • 정적인 파일들을 관리하는 폴더입니다.
  • 개발에 사용되는 font, image, video 등의 파일을 저장합니다.

📂 stores

  • 상태관리를 위한 state들을 정의하고 관리하는 파일들을 모아둔 폴더입니다.

📂 util

  • Database를 사용하기 위해 DB 관련 정보들을 정의해놓은 파일이 저장된 폴더입니다.

 

💻 Release History


  • 1.5.1 (23.09.19)
    • 마이페이지 수정
  • 1.5.0 (23.09.18)
    • 마이페이지
  • 1.3.0 (23.09.15)
    • Fixed Menu 
  • 1.2.0 (23.09.13)
    • 게시글 수정
    • 게시글 삭제
  • 1.1.0 (23.09.13)
    • 회원가입 시 이메일 중복 체크
    • 검색 시 엔터키 사용 가능
  • 1.0.2 (23.09.08)
    • 기타 버그 수정
  • 1.0.1 (23.09.07)
    • UI 및 기타 버그 수정
  • 1.0.0 (23.09.06) * first release

 

📌 주요 기능


회원

  • 정규 표현식을 사용하여 회원가입 기능 구현
    • 회원가입은 간단하고 안전하게 구현되었습니다.
    • 정규 표현식을 활용하여 사용자가 올바른 정보를 입력할 수 있도록 보장합니다.
  • next-auth를 사용하여 로그인, 로그아웃 기능 구현
    • 강력한 인증 및 세션 관리를 위해 next-auth를 도입했습니다.
    • 사용자는 쉽게 로그인하고 로그아웃할 수 있으며, 보안과 편의성을 동시에 제공합니다.

국비 교육과정 검색

  • 훈련과정 상세정보 출력
    • HRD-Net의 오픈 API를 통해 국비 교육과정 정보를 가져와 사용자에게 제공합니다.
  • 훈련과정 후기 작성
    • 각 교육과정의 상세 정보 페이지에서 사용자들은 훈련 후기를 작성하고 공유할 수 있습니다.
    • 이를 통해 다른 사용자들은 실제 경험을 공유하고 교육과정을 선택하는 데 도움을 받을 수 있습니다.

게시판

  • 게시판 선택 후 글 작성
    • 편리한 글 작성을 위해 하나의 페이지에서 다양한 카테고리를 선택할 수 있습니다.
    • 사용자는 원하는 게시판에 글을 작성하고 공유할 수 있습니다.
  • 사진을 첨부하여 글 작성
    • 사용자는 시각적으로 내용을 보충하고 공유할 수 있습니다.
  • 글쓴이, 작성일자, 조회수 확인
    • 모든 게시물에는 글쓴이, 작성일자 및 조회수 정보가 제공됩니다.
    • 이를 통해 게시물의 신뢰성을 높이고 사용자간의 상호작용을 촉진합니다.
  • 게시글에 대한 댓글 작성
    • 사용자들은 게시글에 댓글을 작성하여 의견을 공유하고 토론할 수 있습니다.
    • 이를 통해 커뮤니티의 활발한 상호작용을 지원합니다.

개발에 도움되는 정보

  • 개발, 공부, 취업, 기타 4개의 카테고리로 분류
    • 다양한 정보를 구분하기 위해 네 가지 주요 카테고리로 정보가 분류됩니다.
    • 각 카테고리는 해당 주제에 관한 유용한 정보를 제공합니다.

 

➕ 추가할 기능


  • 우선순위(1)
    • 비밀번호 찾기
    • 좋아요 기능
  • 우선순위(2)
    • 다크모드
    • 프로필 수정
    • 인기 있는 게시글

 

➖ 수정사항


  • vercel 배포 시 게시글 업로드 시간 개선

 

🤦‍♂️ 개발 중 어려웠던 점


부트스트랩 사용하기

 스스로 디자인에 소질이 없는 것을 알기 때문에 이번 프로젝트에서는 부트스트랩을 사용해보기로 하였다.

 여기서 부트스트랩이란 웹 페이지를 빠르고 쉽게 디자인하고 개발할 수 있도록 도와주는 프론트엔드 프레임워크이다.

 하지만 사용법은 간단했으나 기본 디자인에서 변경하려고 할 때, 소소한 어려움이 있었다. 부트스트랩을 사용하게 되면 ID나 Class가 자동으로 생성되어 일일이 효과를 주고 싶은 요소를 찾아야 되는 번거로움이 있고, 때로는 내가 주고 싶은 효과가 우선순위에 밀려 적용되지 않는 경우가 있었다.

 지금은 꽤나 익숙해졌지만, 처음에는 이러한 작은 어려움들 때문에 개발 시간이 조금은 늘어나기도 했다.

 

회원 기능

로그인 하기 전

 next-auth는 Next.js 애플리케이션에서 사용자 인증 및 세션 관리를 쉽게 구현하기 위한 JavaScript 라이브러리로, 간단한 코드 몇 줄만으로도 회원 기능을 구현할 수 있다. 하지만 회원으로부터 얻고 싶은 데이터나 정규식 등을 추가할 때는 꽤 긴 코드들이 필요하다. 그리고 회원 기능은 보안도 중요하기 때문에 단순 코딩이외에도 신경 쓸 게 많았다. 그래서 많은 공을 들인 만큼 배운 것도 많았다.

로그인 한 후

 DataBase와 통신할 때 오류 처리하는 것에 어려움을 느꼈다. 오류 처리를 안한다고 해서 실행이 안되는 것은 아니지만 통신 과정이나 실수로 인해 오류는 언제든지 발생할 수 있으니 필히 오류 처리를 해야한다. 

상황 혹은 status에 맞게 오류 메시지, 성공 메시지 또는 데이터를 전달하는 것에 이해도가 낮아 처음에는 방황을 했다.

 그래서 try-catch문에 대해 검색을 통해서 공부를 하고, 부족한 부분은 강의나 다른 사람들의 코드를 참고해서 보충 공부를 하였다.

 

검색

검색과 동시에 페이지 이동를 하고 검색 결과를 출력

 메인 페이지에서 검색을 하면 페이지가 이동하는 동시에 검색 결과가 나와야 하기 때문에 props만으로는 구현에 어려움이 있었다.

그래서 state를 관리할 필요가 있었고 Redux는 전에 써본 적이 있고 사용법이 복잡하기 때문에 보다 간단한 zustand를 사용해서 state 관리를 하였다.

 zustand를 사용하여 검색 버튼을 누르면 검색 결과가 state에 저장되고 그 값을 다른 컴포넌트에서 재사용할 수 있기 때문에 원하던 기능을 구현할 수 있었다.

 

HRD API의 URL 구성

 HRD API를 통해서 원하는 데이터를 불러올 때, Query string를 통해 과정 이름이나 페이지 수에 대해 정보를 추가해서 요청하는 것에 어려움을 느꼈다.

 그리고 react-js-pagination 라이브러리를 사용해서 페이지네이션 기능을 구현하였다.


훈련기간 받아오기

첫번째 HRD API로부터 얻는 정보를 통해 두번째 HRD API에서 데이터를 얻으려고 할 때, 요청에 대한 body가 정의되지 않았다는 오류가 발생하였다. 

그래서 결국 다른 props를 통해 정보를 전달하여 두번째 HRD API에서 훈련기간 데이터를 받았다.

 

게시판

페이지네이션

페이지네이션을 구현하기 위해 데이터베이스로부터 한 페이지에 얼마나 데이터를 받아올 지에 대해 고민하였다.

try {
            // 로그인한 유저한 동일한 email의 정보를 가져오기
            const db = (await connectDB).db("forum"); // connectDB()를 호출하여 DB 연결을 얻습니다.
            const result = await db
                .collection("post")
                .find({ board })
                .sort({ createdAt: -1 })
                .skip(perPage * (page - 1))
                // .sort({ createdAt: 1 })
                .limit(perPage)
                .toArray(); // find 결과를 배열로 변환하여 가져옵니다.
            // 성공 시 결과 전달
            const dbCnt = await db.collection("post").countDocuments({ board });
            return res.status(200).json({ result, dbCnt });
        } catch (error) {
            console.error("Error fetching data:", error);
            return res.status(500).json({ error: "Internal server error" });
        }

위와 같이 sort, skip, limit 함수를 통해 내가 원하는 정보들과 정렬 방법을 선택하여 페이지네이션을 구현하였다.

 

textarea 줄바꿈까지 출력

 textarea 태그를 통해 사용자가 입력한 데이터를 줄바꿈까지 포함하여 있는 그대로 출력하고 싶은데, 일반적인 방법으로는 줄바꿈은 되지 않고 한 줄로 모든 내용이 출력되었다. 

 그래서 여러 방법을 찾아보니 pre태그를 사용하면 줄바꿈까지 포함되어 사용자가 입력한 그대로를 출력할 수 있다.

 

Warning: Only plain objects can be passed to Client Components from Server Components. Objects with toJSON methods are not supported. Convert it manually to a simple value before passing it to props. (경고: 일반 개체만 Server Components에서 Client Components로 전달할 수 있습니다. toJSON 메서드가 있는 개체는 지원되지 않습니다. props로 전달하기 전에 간단한 값으로 수동으로 변환합니다.)

id값을 string으로 형변환하여 오류를 수정하였다.

 

작성

 서버에 데이터를 전달할 때 form 형식을 많이 사용하여 formData() 함수를 통해 폼데이터를 만들어 전달하려고 했으나 FormData() 함수가 제대로 작동하지 않았다.

 그래서 아래와 같이 직접 변수에 저장하여 서버에게 데이터를 전달하였다.

let data = {};
        const title = e.target.title.value;
        const content = e.target.content.value;
        const board = selectValue;
        const view = e.target.view.value;

        if (src) {
            const image = src;
            data = { title, content, board, view, image };
        } else {
            data = { title, content, board, view };
        }

 

🚫 개발 중 만났던 오류


SyntaxError: Unexpected token < in JSON at position 5

발생원인

  • POST 방식으로 json 데이터가 전송되지 않은 경우
  • 통신 코드에서 Accept에 application/json을 명시하지 않은 경우
  • 코드 내에 오타가 있을 경우

해결방법

  • 발생원인을 토대로 오류 수정

 

TypeError: (0 , util_database__WEBPACK_IMPORTED_MODULE_0_.connectDB) is not a function

발생원인

  • DataBase와 연동하는 과정에서 connectDB 키워드를 인식하지 못해 발생하는 오류

해결방법

  • 연동하는 코드 내에서 connectDB에 붙어있는 소괄호를 지우면 오류가 해결됨.

 

TypeError: Super expression must either be null or a function

발생원인

  • 클라이언트 컴포넌트에서만 사용할 수 있는 키워드들을 서버 컴포넌트에서 사용하여 발생하는 오류

해결방법

  • 해당 컴포넌트 상단에 "use client"를 입력하면 클라이언트 컴포넌트로써 해당 컴포넌트를 사용할 수 있음

 

Error: NextRouter was not mounted.

발생원인

  • next 13 + app directory + "use client" 키워드를 사용할 때는 'next/router' 즉, useRouter를 사용할 수가 없다.

해결방법

  • useNavigation을 사용하면 된다. 
  • 단, useNavigation에는 query 등의 정보가 필요한 경우에는 usepathname를 같이 사용해야 한다.

 

npm ERR! code EACCES

발생원인

  • 맥OS에서 npm 패키지를 설치하려고 할 때, 파일 또는 경로에 대한 액세스 권한이 부족하여 발생

해결방법

  • npm install 앞에 sudo를 붙여 관리자 권한으로 설치하면 문제 해결
  • Password는 Mac의 비밀번호를 입력하면 된다.

 

🛠️ 개발과정에서 부족한 점과 배운 점


부족한 점

서버컴포넌트

 검색 알고리즘에 유리하고, 빠른 로딩 속도를 구현할 수 있는 서버 컴포넌트의 장점을 충분히 살리지 못하였다.

기존 React 개발에 익숙해져있는 상태로 next.js를 활용하여 개발을 하다보니 편한 클라이언트 컴포넌트를 자연스럽게 더 많이 사용하였다.

그래서 다음 프로젝트부터는 모든 기능들을 컴포넌트 단위로 더 나누어 최대한 많이 서버 컴포넌트의 장점을 활용할 수 있도록 해야겠다.

 

AWS 요금 납부

 개발 초기에 오로지 기능 구현에만 집중하여 보안 이슈에 대해서는 생각하지 못했었다. 그래서 AWS S3 key 값이나 DB key 값들을 숨기지 않고 그대로 깃허브에 올리는 치명적인 실수를 하고 말았다.

 그래서 결국 무료 사용량을 초과하여 약 25,000원 정도의 요금을 납부하게 되었고, 그 후로는 보안 이슈에 대해 공부를 하게 되어 다시는 이러한 일이 없도록 다양한 조치를 취했다.

 

배운 점

  • 굉장히 짧고 적은 코드만으로도 해당 프로젝트의 성능과 보안적인 문제를 초래할 수 있다는 것을 알게 되었다.
  • 기능 혹은 그보다 더 작은 단위를 컴포넌트화를 하면서 오류 수정에도 용이하며 다른 기능을 추가할 때도 더 편하다는 것을 알게 되었다.
  • 처음 마주하고 막히는 문제들이 있더라도 어떻게든 해결한 방법이 있으며, 또는 약간은 다른 방식으로 비슷하게 구현할 수 있다는 것을 알게 되었다.

 

 

 

728x90