함께 사서 나누는 소비 방식을 통해 개인의 비용 부담을 완화하고, 자원 낭비를 줄이는 효율적 소비를 할 수 있는 서비스를 제공한다.
🔗 서비스 바로가기
🎨 Storybook 바로가기
📄 최종 발표 자료 바로가기
📼 풀버전 시연 영상 바로가기
💡 [프론트엔드 단독 데모 환경 안내]
본 프로젝트는 백엔드 서버(AWS) 인프라 유지보수 기간이 종료되어,
현재 실무 면접관님들의 원활한 리뷰를 위해 프론트엔드 단독 환경(Mock Data) 으로 전환하여 데모를 제공하고 있습니다.
- 실제 API 연동 화면은 위 풀버전 시연 영상을 통해 확인하실 수 있습니다.
- Mock 전환 구현 방식은 아래 Demo 환경 전환 내역을 참고해 주세요.
- 소분/장보기 모임 생성: 함께 구매하고 나누는 모임 개설
- 댓글 소통: 주최자와 참여자 간의 대화 및 조율
- 모임 관리: 참여 신청, 확정, 거절, 강퇴 등 운영 기능 제공
- 모임 탐색: 카테고리, 지역, 키워드 기반 검색
- 마이페이지: 주최 및 참여 모임 조회와 리뷰 작성
- 간편 로그인: 카카오 계정 연동 로그인
- 코어:
TypeScript,Next.js - 스타일링:
Tailwind CSS - 상태 관리:
Zustand - 테스트:
Jest - 디자인 시스템:
Storybook - CI/CD:
GitHub Actions
| 소분 모임 등록 |
|---|
![]() |
| 소분 모임 댓글 (대댓글, 비공개 댓글 작성 및 수정) |
|---|
![]() |
| 소분 모임 참여 확인 (확정, 거절, 강퇴, 마감) |
|---|
![]() |
| 리뷰 작성 및 조회 |
|---|
![]() |
| 이름 | 프로필 | 개발 내용 |
|---|---|---|
| 이영록 (팀장) | 마이페이지 내 프로필 조회 및 수정 구현 리뷰 조회/작성 기능 구현 마이페이지 내 참여한/주최한/찜한 모임 조회 공용 컴포넌트 개발 + 스토리북 및 테스트 코드 작성 Husky를 통한 커밋 단계 코드 검사 자동화 검색 기능 |
|
| 김동현 | 소분/장보기 모임 목록/상세페이지 기능 구현 공용 컴포넌트 개발 + 스토리북 및 테스트 코드 작성 프로젝트 초기 환경 구성 및 App Router·Jest 테스트 환경 세팅 SEO 최적화 next의 미들웨어 기반 인증 라우팅 제어 next-bundle-analyzer를 활용한 번들 사이즈 분석 및 최적화 |
|
| 류미성 | 소분/장보기 모임 수정 및 삭제 기능 구현 Storybook 환경 세팅 및 Chromatic 자동 배포 설정 공용 컴포넌트 개발 + 스토리북 및 테스트 코드 작성 Jest를 활용한 컴포넌트 테스트 코드 작성 next-bundle-analyzer를 활용한 번들 사이즈 분석 및 최적화 Vercel을 이용한 서비스 배포 |
|
| 최지희 | 소셜 로그인 (카카오톡) 기능 구현 프로필 생성 페이지 구현 공용 컴포넌트 개발 + 스토리북 및 테스트 코드 작성 |
2025.09 ~ 2025.11 (2개월)
백엔드 서버(AWS)의 인프라 유지보수 기간이 종료되어 실 API 호출이 불가능한 상태입니다.
포트폴리오 리뷰어가 실제 화면 흐름을 직접 확인할 수 있도록, API 의존성을 프론트엔드 레이어에서 분리하고 Mock 데이터 기반의 데모 환경으로 전환하였습니다.
실제 API 연동 영상: 풀버전 시연 영상 바로가기
// Before
const protectedRoutes = ['/mypage', '/shopping/register', '/dividing/register'];
// After (DEMO)
const protectedRoutes = ['/mypage', '/shopping/register' /* '/dividing/register' */];/dividing/register 경로를 인증 보호 목록에서 임시 제외하여,
로그인 없이도 모임 등록 화면을 시연할 수 있도록 처리했습니다.
const MOCK_EMPTY_RESPONSE = {
data: { content: [], sliceInfo: { currentPage: 0, size: 10, hasNext: false } },
};
export const getDividingListApi = async (query: URLSearchParams) => {
// [DEMO] 백엔드 없이 시연 가능하도록 API 호출 차단
return MOCK_EMPTY_RESPONSE;
// ...기존 axiosInstance 호출 코드
};실제 API 호출 전에 early-return으로 Mock 응답을 반환합니다.
기존 코드 로직은 그대로 유지하여 API 재연동 시 주석 한 줄만 제거하면 복구됩니다.
export const getCommentApi = async (meetingId: string, query: URLSearchParams) => {
// [DEMO] 시연용 demo 페이지에서 API 호출 차단
if (meetingId === 'demo') {
return { data: { content: [], sliceInfo: { ... }, totalElements: 0 } };
}
// ...기존 axiosInstance 호출 코드
};
export const getCommentCountApi = async (meetingId: string) => {
if (meetingId === 'demo') return 0;
// ...기존 axiosInstance 호출 코드
};meetingId === 'demo' 조건 분기를 통해 실 데이터 흐름을 건드리지 않고
데모 라우트(/dividing/demo)에서만 Mock 응답을 반환합니다.
const MOCK_MEETING_DETAIL: MeetingDetailType = {
id: 9999,
title: '유정란 90구 소분 모집',
location_dep0: '서울특별시',
// ...
};
const MOCK_COMMENTS_LIST: CommentsListType = {
content: [],
sliceInfo: { currentPage: 0, size: 10, hasNext: false },
totalElements: 0,
};
// id가 'demo'이면 API 전체 건너뛰고 목 데이터로 렌더링
if (meetingId === 'demo') {
return (
<section>
<DetailHeader />
<DynamicDetailAsideWrapper meetingDetail={MOCK_MEETING_DETAIL} isAuthor={true} ... />
<DynamicCommentSectionWrapper commentsList={MOCK_COMMENTS_LIST} ... />
</section>
);
}/dividing/demo 경로 접근 시 실제 API 없이 정적 Mock 데이터로 상세 페이지 전체를 렌더링합니다.
generateMetadata도 동일하게 분기 처리하여 SEO 메타태그도 정상 동작합니다.
// [DEMO] 가짜 유저 세션 — 항상 로그인된 것으로 처리
const MOCK_USER = { userId: 1, userName: '소분소분', userNickname: '소분왕', ... };
// useUserLocation 대신 목 위치 데이터 사용
const userLocation = MOCK_USER.userLocation;
const hasLocation = true;
// useMutation 제거 → 로컬 시뮬레이션
const isPending = false;
const onSubmit = (data: DividingFormData) => {
console.log('[DEMO] 등록 폼 제출 데이터:', data);
success('모임이 성공적으로 등록되었어요!');
router.push('/dividing/demo'); // Mock 상세 페이지로 리다이렉트
};실제 useMutation + dividingRegisterApi 호출을 제거하고,
폼 제출 시 성공 토스트를 띄운 뒤 Mock 상세 페이지(/dividing/demo)로 리다이렉트합니다.
위치 정보도 useUserLocation 훅 대신 Mock 세션 데이터로 대체하여 네트워크 오류 없이 폼이 동작합니다.
middleware.ts—'/dividing/register'주석 해제getDividingListApi.ts— early-return 블록 제거getComment.ts/getCommentCount.ts—if (meetingId === 'demo')분기 제거dividing/[id]/page.tsx—MOCK_MEETING_DETAIL,MOCK_COMMENTS_LIST선언 및demo분기 제거dividing/register/page.tsx—MOCK_USER제거,useUserLocation/useMutation/dividingRegisterApi원복



