Main

GitHub

EB Community

2024.04 - 2024.05 (개인 프로젝트)

프로젝트 배경 및 목적

Next.js 공식문서의 App Router Learn과정에서 소개하는 다양한 기능들을 직접 구현해보며 학습하고자 개발한 커뮤니티 사이트입니다.

주요 기능

- GitHub 소셜 로그인 및 이메일 기반 로그인 기능

- 제목 기반 게시글 검색 및 주간 인기 게시글 노출

- 게시글 작성·수정·삭제, 추천·비추천, 댓글 작성 및 관리 기능

- 관리자 대시보드를 통한 회원 권한 관리 및 사이트 통계 표시

기술 스택

TypeScript

TypeScript

Next.js

Next.js

Tailwind CSS

Tailwind CSS

MongoDB

MongoDB

Vercel

Vercel

NextAuth

NextAuth

기능 상세 설명

- 소셜 및 자체 로그인 기능

community-login-page

• NextAuth.js를 기반으로 GitHub 소셜 로그인 기능과 이메일 기반의 로그인 기능을 함께 제공합니다.

• 이메일 회원가입 시, 입력한 비밀번호는 bcrypt로 해싱하여 저장하도록 했습니다.

- 게시글 검색 및 인기글 노출 기능

community-main-page

• 게시글 목록에서 제목 키워드로 게시글을 검색할 수 있는 기능을 제공하며, 주간 조회수·추천수 기준으로 인기 게시글을 별도 영역에 표시합니다.

• useSearchParams, usePathname 등의 Next.js 훅을 활용하여 검색/페이지네이션 기능을 구현했습니다.

- 게시글 및 댓글 관리 기능

community-detail-page

• 로그인한 사용자는 게시글 및 댓글을 자유롭게 작성·수정·삭제할 수 있도록 하였고, 게시글에 대한 추천·비추천 기능도 제공합니다.

• 작성 및 수정 시, 폼 유효성 검사를 수행하도록 했습니다.

- 관리자 대시보드 기능

community-dashboard
community-user-service

• 총 사용자 수, 게시글 수, 오늘의 방문자 수를 카드 및 차트 형태로 시각화했습니다.

• 회원 관리 페이지에서 사용자 검색 및 사용자 권한 변경이 가능합니다.

• middleware 기능을 활용해 관리자 권한이 없는 사용자의 접근을 제한하고 있습니다.

발생한 문제 및 해결 과정

- 닉네임 변경 사항이 반영되지 않는 문제 해결

초기에는 사용자 닉네임을 간편하게 조회하기 위해, NextAuth.js의 jwt 및 session 콜백을 커스텀하여 세션 객체에 닉네임을 포함시켰습니다.

하지만 이후 닉네임 변경 기능이 추가되면서, 세션이 갱신되기 전까지 변경 사항이 반영되지 않는 한계가 드러났고

이에 따라 닉네임은 세션에 저장하지 않고, 사용자 ID를 기준으로 데이터베이스에서 실시간으로 조회하는 방식으로 전환했습니다.

이를 통해 변경 가능성이 있는 정보는 세션보다는 데이터베이스를 통한 조회 방식이 더 안정적이고 일관된 접근임을 실무적으로 체감할 수 있었습니다.

- 게시글 신고 처리 로직 개선

초기에는 사용자가 게시글 신고 버튼을 누르면, 해당 게시글의 is_reported 필드를 즉시 true로 변경하는 방식으로 구현했습니다.

하지만 단 한 명의 신고만으로 게시글이 신고 처리되는 방식은 신뢰성이 떨어진다고 판단해, 일정 수 이상의 신고가 누적될 때만 is_reported 값을 변경하도록 로직을 개선했습니다.

이를 위해 신고한 사용자들의 ID를 배열로 저장하고, 동일 사용자의 중복 신고를 막는 검증을 추가했으며, 해당 배열의 길이가 5 이상일 때만 게시글이 신고 처리되도록 구현했습니다.

이 과정을 통해 단순한 기능 구현을 넘어, 사용자 행동 기반의 조건 처리와 데이터 구조 설계 경험을 쌓을 수 있었습니다.

배운 점

- Tailwind CSS와 clsx를 활용한 반응형 스타일링 및 유틸리티 기반 CSS 설계 방식 학습

- NextAuth.js를 활용한 인증 흐름 이해 및 로그인 기능 구현 경험

- Server Component를 활용한 서버 측 데이터 패칭 방식 학습

- Suspense를 활용한 스트리밍 렌더링 처리 방식에 대한 이해

- Next.js의 클라이언트 훅을 활용한 검색 및 페이지네이션 처리 방식 학습

- Next.js의 동적 라우팅, Middleware, Server Action 기능의 사용 방법 학습

- react-hook-form과 zod를 통합한 폼 유효성 검사 방식 학습

- 서버리스 아키텍처 기반의 CRUD 기능 설계 및 구현 경험

- MongoDB 연결 설정 및 기본적인 쿼리 작성·데이터 조작 방식 이해

회고

저는 Next.js의 새로운 버전을 학습하기 위해 공식 문서에서 제공하는 App Router 학습 과정을 직접 따라가며 구현해보는 방식으로 기초를 다졌습니다.

그 과정에서 학습한 내용을 더 깊이 이해하고 실제로 응용해보기 위해서 스스로 기획한 커뮤니티 웹사이트를 개발하고자 하였고,

공식 튜토리얼에서 사용된 UI와 구현 방식은 참고하되, 기획한 서비스에 맞춰 데이터 구조 및 데이터베이스를 독자적으로 설계하여 완성한 프로젝트입니다.

이후에는 단순히 Next.js를 학습하는 것을 넘어, 실사용 가능한 커뮤니티 웹사이트가 되도록 프로젝트의 완성도를 높이는 데 집중했으며,

현재도 실사용 시나리오를 기반으로 지속적으로 기능을 개선하고 코드를 리팩토링하며 유지보수 중입니다.

teTrips

2024.06 - 2024.09 (4인 팀 프로젝트)

프로젝트 배경 및 목적

여행을 준비할 때 가장 어려운 점 중 하나는 여러 사람의 일정과 의견을 조율하는 과정이라고 생각합니다.

서로 다른 시간대에 의견을 나누고, 엑셀이나 메신저로 계획을 공유하다 보면 번거롭고 비효율적인 경우가 많습니다.

이러한 문제를 해결하고자, 여러 명이 동시에 여행 일정을 실시간으로 편집하고 조율할 수 있는 서비스를 개발하였습니다.

기여한 기능

- 여행 계획 제작·편집 페이지 UI/UX 설계 및 반응형 디자인 구현

- 서버리스 아키텍처 기반의 여행 계획 CRUD 기능

- Yjs 기반의 실시간 동시 편집 기능

- NCP Maps 서비스를 활용한 지도 렌더링, 마커 동기화·경로 연결 및 인터랙션 기능

- 외부 API들을 활용한 네이버 지도 검색 기능 및 동선 최적화 기능

- 여행 계획 이미지 저장 기능

기술 스택

TypeScript

TypeScript

Next.js

Next.js

Tailwind CSS

Tailwind CSS

Spring Boot

Spring Boot

MongoDB

MongoDB

Zustand

Zustand

Docker

Docker

NCP

NCP

기여한 기능 상세 설명

- 여행 계획 편집 페이지 UI/UX 설계 및 구현

trip-detail-page
trip-detail-2
trip-detail-3

• 여행 날짜 별로 활동 시작 시간과 출발지·도착지·여행지 목록을 편집할 수 있습니다.

• 추천 장소 목록을 확인하거나 네이버 지도 검색을 통해 장소를 탐색할 수 있고 여행지에 추가할 수 있습니다.

• 여행지 별로 메모를 입력하거나 머무는 시간을 입력할 수 있으며, 드래그 앤 드롭으로 여행지 방문 순서를 변경할 수 있습니다.

- 네이버 지도 연동 및 동선 시각화

trip-map

• 줌 인, 줌 아웃이 가능한 네이버 지도를 제공합니다.

• 여행지 추가 시 자동으로 지도에 마커로 표시되며, 마커 클릭 시 장소 정보를 확인할 수 있습니다.

• 날짜 별로 동선을 시각화하여 표시하고 여행지 방문 순서에 따른 마커 번호를 표시합니다.

- 실시간 동시 편집 기능 및 실시간 채팅 UI 구현

trip-sync

• 여행 계획 편집 과정에서 초대 링크를 복사한 뒤 공유하여, 다른 사용자를 초대할 수 있습니다.

• 초대된 사용자들과 동시에 여행 계획을 편집하고 변경 사항을 실시간으로 공유할 수 있습니다.

• 백엔드 채팅 서버와 연동해 실시간으로 메시지를 송수신하고, 전달받은 데이터를 가공하여 채팅 UI에 반영했습니다.

- 동선 최적화 기능

trip-path

• 동선 최적화 기능 사용 시 TMAP 경유지 최적화 API를 활용하여, 최적화된 동선을 바탕으로 방문 순서가 자동으로 재정렬됩니다.

• 장소별 도착시간이나 출발 시간등의 세밀한 결과를 확인할 수 있습니다.

발생한 문제 및 해결 과정

- 동시 편집 시 데이터 충돌 문제

여행 계획 데이터를 단일 배열로 관리하면서 동시에 동일 데이터를 편집할 때 충돌이 발생했습니다.

이를 해결하기 위해 Yjs 문서를 중첩 Map 구조로 변경하여 관리했고, 충돌 없이 세밀한 동시 제어가 가능해졌습니다.

이 경험을 통해 사용자 상호 작용을 고려한 데이터 구조 설계의 중요성을 느낄 수 있었습니다.

- 실시간 사용자 아이콘 표시 문제

참여 중인 사용자의 아이콘을 상단에 표시하는 기능에서 실시간성이 보장되지 않는 문제가 있었습니다.

이를 아이콘 목록까지 Yjs 문서로 관리하고 y-websocket을 적용하여 안정적인 실시간 동기화를 구현했습니다.

배운 점

- CRDT 알고리즘에 대한 이해 및 Y.js 및 y-websocket을 활용한 동시 편집 기능 구현 경험

- Naver Maps API를 활용한 동적 지도 마커 렌더링, 커스텀 오버레이, 폴리라인 구현 경험

- Naver Developers 검색 API, TMAP 경유지 최적화 API 등 외부 API 서비스를 활용한 데이터 처리 경험

- 라이브러리를 활용한 드래그 앤 드롭 기능 및 DOM 기반 이미지 저장 기능 구현 경험

- SockJS와 Stomp를 활용한 채팅 서버 연동 및 실시간 메시지 송수신 처리 경험

회고

teTrips는 네이버 클라우드 캠프의 데브옵스 교육 과정에서 진행한 팀 프로젝트로,

복잡한 사용자 인터랙션을 다루는 개발 과정에서 반복적인 개선과 리팩토링을 거치며 기능 확장성과 유지보수성을 고려한 설계의 중요성을 느낄 수 있었습니다.

또한, 협업 초기에는 일정 조율과 작업 분담에서 어려움이 있었지만, Jira와 Confluence를 통한 작업 공유와 Git-Flow 브랜치 전략 도입으로 협업이 점차 안정되었고, 이를 통해 소통과 협업 도구의 중요성을 실감할 수 있었습니다.

KTWiz 웹페이지 개선 프로젝트

2024.12 - 2025.01 (5인 팀 프로젝트)

프로젝트 배경 및 목적

프로젝트 요구사항에 맞춰 야구 정보를 더 재밌게 전달할 수 있도록 KTWiz의 웹사이트를 개선했습니다.

기여한 기능

- Tailwind CSS 기반 공통 컴포넌트 설계 및 구현

- 포토, 영상, 팬 게시판, 마이 페이지의 UI/UX 설계 및 반응형 웹 구현

- IntersectionObserver를 활용한 무한 스크롤 기능

- 이미지 확대·축소 및 자동 전환이 가능한 이미지 캐러셀 기능

- Supabase Realtime 기반의 실시간 응원 오픈채팅 기능

- 게시글 및 댓글 작성·수정·삭제 기능

- 닉네임 변경 및 좋아요한 영상 목록 조회 기능

기술 스택

TypeScript

TypeScript

Next.js

Next.js

Tailwind CSS

Tailwind CSS

Supabase

Supabase

Vercel

Vercel

기여한 기능 상세 설명

- 포토 및 영상 페이지 & 무한 스크롤 기능

ktwiz-photo-page
ktwiz-video-page
ktwiz-video-detail-page

• IntersectionObserver 기반의 무한 스크롤 기능을 도입하여 콘텐츠 탐색 흐름을 자연스럽게 개선했습니다.

• 조회수 기반 인기 영상 목록과 이전/다음 영상 목록을 제공하여 콘텐츠 접근성과 사용자 몰입도를 높였습니다.

- 이미지 슬라이드 기능

ktwiz-photoslide

• 포토 페이지에서 이미지를 클릭하면 슬라이드 모드로 전환되어 전체 사진을 순차적으로 탐색할 수 있습니다.

• 좌우 드래그를 통한 이전/다음 이미지 전환이 가능하며 확대·축소 및 5초 간격의 자동 이미지 전환도 가능합니다.

- 팬 게시판 페이지 & 실시간 응원 오픈채팅 기능

ktwiz-fanpage

• 로그인한 사용자는 실시간 응원 오픈채팅에 참여할 수 있습니다.

• 게시글 제목 또는 내용으로 키워드를 검색해 원하는 게시글을 찾을 수 있습니다.

- 게시글 및 댓글 작성·수정·삭제 기능

ktwiz-post-create
ktwiz-post-edit

• 로그인한 사용자는 게시글과 댓글을 작성, 수정, 삭제할 수 있습니다.

• 게시글 작성 시 최대 3장의 이미지를 첨부할 수 있습니다.

- 마이페이지

ktwiz-mypage

• 마이페이지에서 닉네임 변경이 가능하며 좋아요한 영상 목록을 확인할 수 있습니다.

발생한 문제 및 해결 과정

- 이미지 리소스가 403 오류로 로드되지 않는 문제

외부 이미지 리소스가 403 오류로 차단되는 현상을 CORS 정책 문제로 판단하고, next/image 컴포넌트가 서버 측에서 이미지를 프록시 요청하는 특성을 활용해 기존 img 태그를 전부 next/image 컴포넌트로 교체할 것을 제안했습니다.

그 결과, 별도의 서버 설정 없이도 문제를 팀 내부적으로 해결할 수 있었고, 이미지 최적화 기능을 통한 성능 개선 효과도 함께 얻을 수 있었습니다.

- 모든 페이지가 동적 렌더링되는 문제

루트 레이아웃에 위치한 헤더 컴포넌트가 cookies() 함수를 사용해 서버 측에서 세션을 조회하면서,

정적으로 렌더링될 수 있는 페이지까지 모두 동적으로 렌더링되는 문제가 발생했습니다.

이를 해결하고자 세션 조회를 클라이언트 측으로 전환해 정적 렌더링을 복원했지만, 초기 렌더링 시점과 실제 로그인 상태 간의 불일치로 인해 UI 깜빡임 및 로그인 상태 오표시와 같은 부작용이 발생했습니다.

결국 로그인 여부에 따라 헤더 UI가 달라지는 구조에서는 정적 렌더링의 이점보다 정확한 세션 반영을 통한 일관된 사용자 경험이 더 중요하다고 판단하여, 모든 페이지를 SSR로 전환하고 서버 측 세션 조회 방식을 유지했습니다.

배운 점

- 공통 컴포넌트 설계

- 웹 성능 측정 방법 및 웹 성능 최적화 방법

- next/image 컴포넌트가 제공하는 이미지 최적화 방식

- Supabase Realtime 및 Supabase Storage 활용 방법

회고

KTWiz 웹페이지 개선 프로젝트는 고용노동부가 주관하는 미래내일 일경험 사업의 일환으로,

실제 KT 재직 중인 멘토님의 지도 아래 진행한 팀 프로젝트였습니다.

기존 웹사이트의 문제점을 분석하고 개선하는 과정에서 사용자 경험을 고려한 UI/UX 설계에 집중하며 사용자 중심의 설계 감각을 한층 키울 수 있었습니다.

또한, 세부 기능을 다듬고 성능을 개선하는 과정을 거치며 단순한 구현을 넘어 서비스 완성도를 높이는 개발자의 시각을 갖추게 되었습니다.

Loaduo

2024.03 - 2024.06 (개인 프로젝트)

www.loaduo.com

프로젝트 배경 및 목적

로스트아크 유저들이 단기적인 파티 모집이 아니라, 꾸준히 함께 레이드를 즐길 수 있는 1:1 파트너(깐부)를 찾을 수 있도록 돕는 플랫폼을 구축했습니다.

주요 기능

- 페이지 UI/UX 설계 및 반응형 디자인

- 필터링을 통한 구인 글 조회

- 구인 글 작성·수정·삭제 기능

- 로스트아크 api를 활용한 캐릭터 검색 기능

- 공격대 시뮬레이터 기능

기술 스택

TypeScript

TypeScript

Next.js

Next.js

Tailwind CSS

Tailwind CSS

MongoDB

MongoDB

Vercel

Vercel

기능 상세 설명

- 필터링을 통한 구인 글 조회

loaduo-main-page

• 아이템 레벨, 서버 등을 필터링하여 구인 글을 조회할 수 있습니다.

- 구인 글 작성·수정·삭제·신고 기능

loaduo-write

• 캐릭터 닉네임을 기반으로 조회된 정보를 활용하여 구인 글을 작성할 수 있습니다.

• 구인 글 작성 시 입력했던 비밀번호를 통해 수정 및 삭제가 가능합니다.

• 신고하기 버튼을 통해 신고할 수 있습니다.

- 캐릭터 검색 기능

loaduo-search

캐릭터 닉네임을 기반으로 검색하여 해당 캐릭터의 스펙 관련 정보를 확인할 수 있습니다.

해당 캐릭터가 작성한 구인 글 목록이 함께 표시됩니다.

- 공격대 시뮬레이터 기능

loaduo-builder

캐릭터 닉네임을 기반으로 공격대에 추가하여 파티 별 시너지 조회가 가능합니다.

드래그 앤 드롭을 통해 파티 변경이 가능합니다.

발생한 문제 및 해결 과정

- 커스텀 캐싱 전략 적용

로스트아크 Open API는 분당 호출 제한이 존재하며, 공식 문서에서도 이를 고려한 캐싱 전략을 권장하고 있습니다.

이에 따라 API 응답 데이터를 MongoDB에 저장하고, 저장된 데이터의 업데이트 시간을 기준으로 외부 API를 호출할지 여부를 판단하는 구조로 개선했습니다. 이를 통해 불필요한 외부 요청을 줄이고, 호출 제한을 효율적으로 관리할 수 있었습니다.

- 모바일 환경에서 발생한 무한 렌더링 오류

모바일 환경에서 Headless UI의 특정 컴포넌트가 화면 높이를 초과하면서 옵션 리스트가 무한 렌더링되는 문제가 발생했습니다.

원인을 분석해 옵션 리스트의 최대 높이를 제한하고, 동일한 값을 선택 시 불필요한 상태 업데이트를 방지하여 문제를 해결했습니다.

- 삭제 기능 개선

초기에는 사용자가 직접 삭제하거나 일정 횟수 이상 신고된 모집 글을 데이터베이스에서 물리적으로 삭제하는 방식을 사용했습니다. 그러나 운영 과정에서 삭제된 글의 기록을 확인할 수 없어 불편함이 발생했습니다.

이를 개선하기 위해 is_deleted라는 상태 필드를 추가하여, 실제 데이터는 보존하되 삭제 여부만 표시하는 논리적 삭제 방식으로 변경했습니다. 이후 클라이언트는 이 값을 기준으로 삭제된 글을 화면에서 노출하지 않도록 처리했습니다.

- 허용되지 않은 데이터 저장 문제

특정 필드에서 빈 값을 허용하지 않음에도 불구하고, 콘솔 조작을 통해 빈 데이터가 저장되는 문제가 발생했습니다.

당시 react-hook-form과 zod를 통합하여 클라이언트와 서버 모두 동일한 스키마로 유효성 검사를 수행하고 있었으나, 스키마 정의가 충분히 엄격하지 않았던 것이 원인이었습니다.

이에 따라 스키마를 보다 정밀하게 작성하여, 허용되지 않는 값이 저장되지 않도록 검증을 강화함으로써 문제를 해결했습니다.

배운 점

- 상황에 맞는 캐싱 전략 설계 경험

- MongoDB 인덱스 최적화

- 메타 태그를 통한 SEO 개선

- 실 서비스 환경을 고려한 비용 관리 경험

회고

loaduo는 제가 로스트아크를 즐기며 직접 필요성을 느꼈던 서비스를 현실화한 프로젝트였습니다.

단순한 토이 프로젝트가 아닌 실제 운영을 전제로 했기에, 다양한 사용 시나리오를 고려하고 에러 처리 및 악성 유저 대응까지 세심하게 준비하여 런칭했습니다.

하지만 운영 과정에서 마주한 문제들은 사전 대비만으로 해결할 수 없는 경우가 많았습니다.

예상치 못한 Form 데이터 조작, 사용자들의 버그 제보를 통해 발견된 오류 등을 겪으며,

서버 측 유효성 검증의 중요성과 다양한 환경에서의 철저한 테스트 필요성을 절실히 깨달을 수 있었습니다.

이 경험을 통해 단순히 기능을 구현하는 것과 실제 서비스가 안정적으로 운영되는 것은 전혀 다른 차원의 문제임을 체감했고, 개발자로서 한 단계 성장할 수 있는 계기가 되었습니다.