mindLog Frontend
AI 기반 감정 분석 및 정신 건강 관리 웹 서비스
mindLog는 사용자가 AI와 상담하며 감정을 기록하고, 주간/월간 리포트로 감정 패턴을 분석하며 정신 건강을 관리하는 서비스입니다.
프로젝트: KT Cloud Tech Up 실무 통합 프로젝트
🚀
- 이메일/비밀번호 로그인
- Oauth 소셜 로그인 (카카오, 구글)
- 자동 토큰 갱신 (Axios 401 인터셉터)
- 회원가입 및 닉네임 설정
- 프로필 관리 (사진, 프로필 정보, 닉네임)
- 월간 출석 캘린더 (달력 형식 출석 기록)
- 주간 도장판 (월-일 요일별 진행 상황)
- 자동 슬라이드 배너 (4초 간격, 3개 배너)
- 주간/월간 리포트 달성률 위젯 (진행도 표시, 애니메이션)
- 세션 진행도 (리포트 생성 가능 조건)
- 감정카드 컬렉션 미리보기 (최근 카드 스크롤)
- 세션 생성 및 관리 (새로운 상담 시작)
- 스트리밍 응답 (실시간 AI 응답 표시)
- 세션 히스토리 (좌측 사이드바 - 이전 대화 목록)
- 세션 상세 조회 (채팅 기록 보기)
- 미완성 세션 모달 (이전 대화 계속하기 옵션)
- 감정 레이블 추가 (상담 완료 후 감정 선택)
- 감정카드 생성 (AI 응답 기반 감정카드 자동 생성 - SVG→PNG 변환)
- 세션 삭제
- 크레딧 부족 경고 (크레딧 부족 시 모달 표시)
- 감정카드 그리드 표시 (생성된 모든 감정카드 전시)
- 카드 날짜 표시 (YYYY.MM.DD 형식)
- 감정카드 상세 보기 (확대 오버레이)
- 감정 색상 범례 (JOY, ANGER, SADNESS, ANXIETY, HOPEFUL, CALM 등)
- 반응형 레이아웃 (화면 너비에 따라 카드 크기 동적 조정)
- 카드 호버 효과 (스케일 및 섀도우 애니메이션)
- 카드 다운로드 (감정카드 이미지 저장)
- 리포트 목록 조회 (주간/월간 리포트 목록)
- 리포트 생성 (주간/월간 선택 후 생성)
- 생성 상태 추적 (생성 중, 분석 중 상태 표시)
- 리포트 상세 보기 (텍스트 기반 분석 결과)
- 리포트 삭제
- 리포트 생성 실패 처리 (실패 원인 표시)
- 크레딧 소비량 안내 (리포트당 필요 크레딧 표시)
- 크레딧 상품 페이지
- 소형 (200 크레딧, 2,200원)
- 중형 (500 크레딧, 4,900원)
- 대형 (1,200 크레딧, 10,900원)
- 크레딧 상품별 사용 범위 안내
- 토스 페이먼츠 결제
- 결제 성공/실패 페이지
- 크레딧 잔액 표시 (GNB에 실시간 반영)
- 프로필 정보 조회
- 닉네임, 이메일, 성별, 나이, 직업
- 프로필 사진 미리보기
- 프로필 수정 (드로어 형식)
- 닉네임 변경
- 성별 선택 (남/여)
- 나이 선택 (20/30/40)
- 직업 선택 (학생, 직장인, 자영업자, 기타)
- 프로필 사진 업로드
- 결제 내역 조회
- 거래 유형별 표시 (회원가입 보너스, 충전, 리포트 생성 등)
- 거래 시간 (KST 기준)
- 크레딧 증감 표시
- 결제 환불 (결제 취소 가능)
- 로그아웃
- 회원 탈퇴
| 항목 | 기술 | 버전 |
|---|---|---|
| Framework | Next.js (App Router) | 16.1.5 |
| Runtime | React | 19.2.3 |
| Language | TypeScript (Strict) | 5.x |
| 항목 | 기술 | 버전 | 용도 |
|---|---|---|---|
| 전역 상태 | Zustand | 5.0.10 | 사용자, 크레딧, 테마 상태 |
| 서버 상태 | TanStack React Query | 5.90.20 | API 캐싱, 자동 동기화 (staleTime: 1분) |
| 폼 상태 | React Hook Form | 7.71.1 | 폼 검증 및 관리 |
| 검증 | Zod | 4.3.6 | 타입 안전 스키마 (API 응답) |
| 항목 | 기술 | 버전 | 용도 |
|---|---|---|---|
| CSS | Tailwind CSS | 4.x | 유틸리티 기반 스타일 |
| CSS 변수 | @tailwindcss/postcss | 4.x | PostCSS 처리 |
| UI 라이브러리 | Radix UI | 1.4.3 | 접근성 컴포넌트 기반 |
| UI 컴포넌트 | shadcn/ui | - | Button, Dialog, Input, Tabs, Popover 등 30+ 컴포넌트 |
| 애니메이션 | Framer Motion | 12.38.0 | 스트리밍 응답, 카드 전환, 모달 |
| 애니메이션 | Motion | 12.38.0 | 추가 애니메이션 유틸 |
| 아이콘 | Lucide React | 0.563.0 | 통일된 아이콘 셋 |
| 테마 | next-themes | 0.4.6 | 라이트/다크 모드 전환 |
| 차트 | Recharts | 3.8.0 | 리포트 통계 그래프 |
| 날짜 선택 | react-day-picker | 9.14.0 | 캘린더 UI |
| 유틸 | clsx, tailwind-merge | 2.x, 3.4.0 | 클래스명 병합 |
| 항목 | 기술 | 버전 | 용도 |
|---|---|---|---|
| HTTP 클라이언트 | Axios | 1.13.3 | API 요청, 토큰 자동 갱신 (401 처리) |
| Form 입력 | @hookform/resolvers | 5.2.2 | Zod 스키마와 폼 통합 |
| JWT 처리 | jose | 6.2.0 | 액세스/리프레시 토큰 검증 |
| 마크다운 | react-markdown | 10.1.0 | 리포트 텍스트 렌더링 |
| 마크다운 플러그인 | remark-gfm | 4.0.1 | GitHub Flavored Markdown |
| 항목 | 기술 | 버전 | 용도 |
|---|---|---|---|
| 결제 SDK | @tosspayments/payment-sdk | 1.9.2 | 토스 페이먼츠 결제 |
| 이미지 변환 | html-to-image | 1.11.13 | 감정카드 SVG→PNG 변환 |
| 캐러셀 | swiper | 12.1.2 | 배너, 카드 슬라이드 |
| 닉네임 생성 | unique-names-generator | 4.7.1 | 랜덤 닉네임 생성 |
| 항목 | 기술 | 버전 |
|---|---|---|
| 린터 | ESLint | 9.x |
| 포매터 | Prettier | 3.4.2 |
| Tailwind 플러그인 | prettier-plugin-tailwindcss | 0.6.9 |
| 웹 폰트 | Pretendard | 1.3.9 |
| 병렬 실행 | concurrently | 9.2.1 |
src/app/
├── layout.tsx # Root 레이아웃 (Providers 초기화)
├── globals.css # 전역 스타일
├── login/
│ └── page.tsx # 로그인 페이지 (이메일/비밀번호, Oauth)
├── signup/
│ ├── page.tsx # 회원가입 페이지
│ └── nickname/
│ └── page.tsx # 닉네임 설정 페이지
├── auth/
│ ├── kakao/callback/
│ │ └── page.tsx # 카카오 OAuth 콜백
│ └── google/callback/
│ └── page.tsx # 구글 OAuth 콜백
├── api/v1/
│ └── ... # 내부 API 라우트 (토큰 갱신 등)
├── error/
│ └── 506/
│ └── page.tsx # 500 에러 페이지
├── not-found.tsx # 404 페이지
│
└── (main)/ # 인증된 사용자 전용 그룹 라우트
├── layout.tsx # 메인 레이아웃 (GNB, 푸터)
├── page.tsx # 홈 (대시보드)
├── chat/
│ └── page.tsx # AI 채팅 상담 페이지
├── collection/
│ └── page.tsx # 감정카드 컬렉션 페이지
├── report/
│ └── page.tsx # 주간/월간 리포트 페이지
├── shop/
│ └── page.tsx # 크레딧 구매 페이지
├── my/
│ └── page.tsx # 마이페이지
├── about/
│ └── page.tsx # 소개 페이지
├── support/
│ └── page.tsx # 지원/문의 페이지
├── terms/
│ └── [key]/
│ └── page.tsx # 동적 약관 페이지
└── payment/
└── page.tsx # 결제 결과 페이지 (성공/실패)
src/entities/
├── user/ # 사용자 인증 & 프로필
│ ├── api.ts # API: login, signup, getProfile, updateProfile, withdraw
│ ├── model.ts # 타입: User, AuthResponse, UserProfile
│ ├── schema.ts # Zod 검증 스키마
│ ├── store.ts # Zustand: 사용자 상태, 인증 토큰
│ └── index.ts
├── session/ # AI 채팅 세션
│ ├── api.ts # API: createSession, getSession, finalizeSession, deleteSession
│ ├── model.ts # 타입: SessionDetail, FinalizeEvent, SessionList
│ ├── schema.ts # Zod 검증 스키마
│ ├── utils.ts # 세션→감정카드 변환 유틸
│ └── index.ts
├── emotion/ # 감정카드
│ ├── api.ts
│ ├── model.ts # 타입: EmotionType, EmotionCard
│ ├── schema.ts
│ └── index.ts
├── reports/ # 주간/월간 리포트
│ ├── api.ts # API: createReport, getReports, deleteReport
│ ├── model.ts # 타입: Report, ReportStatus, ReportEvent
│ ├── schema.ts # Zod 검증 스키마
│ └── index.ts
├── summary/ # 감정카드 (Collection)
│ ├── api.ts # API: getSummaryList, uploadCardImage
│ ├── model.ts # 타입: SummaryItem, ImageUrl
│ ├── schema.ts
│ └── index.ts
├── credits/ # 크레딧 & 결제
│ ├── api.ts # API: getProducts, getMyCreditgetPaymentHistory, cancelPayment
│ ├── model.ts # 타입: CreditProduct, PaymentHistory
│ ├── schema.ts # Zod 검증 스키마
│ ├── store.ts # Zustand: 크레딧 잔액
│ └── index.ts
├── attendance/ # 월간 출석 & 캘린더
│ ├── api.ts # API: getAttendance(yearMonth)
│ ├── model.ts # 타입: AttendanceResponse
│ ├── schema.ts
│ └── index.ts
└── index.ts
src/features/
├── auth/ # 인증 로직
│ ├── useAuth.ts # Hook: 로그인, OAuth 처리
│ ├── useAuthCallback.ts # Hook: OAuth 콜백 처리
│ └── components/ # 로그인 폼 UI
├── send-message/ # 메시지 전송 (스트리밍)
│ └── ... # 채팅 메시지 전송 로직
├── purchase-credit/ # 크레딧 구매 플로우
│ ├── CreditProductCard.tsx
│ ├── PurchaseConfirmDialog.tsx
│ └── RefundPolicyNotice.tsx
└── index.ts
src/shared/
├── api/
│ ├── axios.ts # Axios 인스턴스 (401 자동 갱신, 인터셉터)
│ └── index.ts
├── ui/ # 30+ 공통 UI 컴포넌트
│ ├── button.tsx
│ ├── dialog.tsx # @radix-ui/react-dialog 래퍼
│ ├── input.tsx
│ ├── tabs.tsx # @radix-ui/react-tabs 래퍼
│ ├── card.tsx
│ ├── status-modal.tsx # 상태 표시 모달
│ ├── toast.tsx # 토스트 알림
│ ├── profile-avatar.tsx
│ ├── ErrorState.tsx
│ ├── ComingSoon.tsx
│ └── ...
├── lib/
│ ├── utils.ts # cn() 클래스 병합 등
│ ├── env.ts # 환경변수 관리
│ ├── chatNavigationStore.ts # 채팅 네비게이션 상태
│ ├── utils/
│ │ ├── cookie.ts # getCookie, setCookie
│ │ ├── parse.ts # 데이터 검증 유틸
│ │ ├── nickname.ts # 닉네임 생성
│ │ └── error.ts # 에러 처리 유틸
│ └── hooks/
│ ├── useGnbTheme.ts # GNB 테마 훅
│ └── ...
└── constants/
src/widgets/
├── gnb/ # Global Navigation Bar
│ ├── gnb.tsx # 상단 네비게이션 바
│ └── ...
├── chat-main-area/ # 채팅 메인 영역
│ ├── ChatMainArea.tsx
│ └── ...
├── chat-sidebar/ # 채팅 사이드바 (세션 목록)
│ ├── ChatSidebar.tsx
│ └── ...
├── emotion-card/ # 감정카드 표시 및 동작
│ ├── EmotionCard.tsx
│ ├── EmotionCardFront.tsx
│ ├── EmotionCardBack.tsx
│ └── ...
└── emotion-color-legend/ # 감정 색상 범례
└── ...
src/components/
├── about/ # 소개 페이지 컴포넌트
├── chat/ # 채팅 관련 컴포넌트
│ ├── ChatAlertModal.tsx
│ ├── ChatCreditModal.tsx
│ ├── ChatNewSessionModal.tsx
│ ├── ChatUnfinishedSessionModal.tsx
│ └── ...
├── my/ # 마이페이지 컴포넌트
│ ├── ProfileEditDrawer.tsx
│ └── ...
└── report/ # 리포트 관련 컴포넌트
├── ReportSidebar.tsx
├── ReportCreationForm.tsx
├── ReportDetail.tsx
├── ReportPolling.tsx
├── ReportError.tsx
├── DeleteReportModal.tsx
├── ReportCreditModal.tsx
└── ...
src/
├── providers/ # React Context Providers
│ ├── query-provider.tsx # React Query (staleTime: 1분)
│ └── theme-provider.tsx # next-themes 프로바이더
├── types/ # 전역 타입
│ ├── credit.ts
│ ├── crisis.ts
│ ├── notification.ts
│ └── index.ts
├── constants/ # 앱 전역 상수
├── mocks/ # Mock 데이터 (개발/테스트)
│ ├── user.ts
│ ├── session.ts
│ ├── emotion.ts
│ ├── report.ts
│ ├── credits.ts
│ └── index.ts
└── middleware.ts # Next.js 미들웨어
git clone https://github.com/8ocket/Frontend.git
cd Frontendnpm install
# 또는
pnpm install.env.example 파일을 참고하여 .env.local 파일을 생성합니다.
cp .env.example .env.local필수 환경 변수:
# API 서버
NEXT_PUBLIC_API_URL=http://localhost:8080/v1
NEXT_PUBLIC_API_BASE_URL=http://localhost:8080
# OAuth
NEXT_PUBLIC_KAKAO_CLIENT_ID=your_kakao_client_id
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your_google_client_id
NEXT_PUBLIC_OAUTH_REDIRECT_URI=http://localhost:3000
# 결제
NEXT_PUBLIC_TOSS_CLIENT_KEY=your_toss_client_key
# 개발 환경
NEXT_PUBLIC_APP_ENV=developmentnpm run dev브라우저: http://localhost:3000
npm run dev:all필수 조건:
- 백엔드: Spring Boot 서버 (
:8080) - AI: Docker (AI 서비스)
npm run dev:turbo# 빌드
npm run build
# 실행
npm run start# 전체 검사 (타입 + 린트 + 포매팅)
npm run check
# 각각 실행
npm run type-check # TypeScript 타입 검사
npm run lint # ESLint 검사
npm run format:check # Prettier 포매팅 검사# ESLint 자동 수정
npm run lint:fix
# Prettier 포매팅
npm run formatnpm run clean각 도메인은 독립적인 폴더:
src/entities/user/
- api.ts # API 요청 함수들
- model.ts # 타입 정의
- schema.ts # Zod 검증 스키마
- store.ts # Zustand 전역 상태
- index.ts # 공개 인터페이스예시: 사용자 프로필 가져오기
// entities/user/api.ts
export const getMyProfileApi = async (): Promise<UserProfileResponse> => {
const response = await api.get<UserProfileResponse>('/user/profile');
return safeParse(UserProfileResponseSchema, response.data);
};
// app/(main)/my/page.tsx
const { data: profile } = useQuery({
queryKey: ['myProfile'],
queryFn: getMyProfileApi,
});React Query: 서버 상태 (API 데이터)
const { data, isLoading } = useQuery({
queryKey: ['sessions'],
queryFn: getSessionsApi,
staleTime: 1000 * 60, // 1분 캐시
});Zustand: 클라이언트 상태 (사용자, 크레딧, 테마)
const { user, setUser } = useAuthStore();
const { totalCredit } = useCreditStore();const schema = z.object({
email: z.string().email('유효한 이메일이 아닙니다'),
password: z.string().min(8, '8자 이상'),
});
const form = useForm({
resolver: zodResolver(schema),
});401 응답 시 자동으로 토큰 갱신:
// shared/api/axios.ts
api.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
// 토큰 갱신 후 재시도
}
}
);// 백엔드에서 SSE로 스트리밍
const stream = await finalizeSessionStream(sessionId);
for await (const event of stream) {
// 실시간 응답 업데이트
}-
세션 생성
createSessionApi()→ 새 세션 ID 획득
-
메시지 전송 (스트리밍)
sendMessageStream()→ 실시간 응답message이벤트로 점진적 업데이트
-
감정카드 생성
finalizeSessionStream()→ AI 분석 감정html-to-image로 SVG→PNG 변환uploadSummaryCardImageApi()→ 이미지 업로드
-
세션 저장
- 로컬 스토어에 히스토리 추가
- React Query 캐시 업데이트
-
리포트 생성 요청
createReportApi(type)→ 생성 시작
-
상태 폴링
ReportPolling컴포넌트로 상태 모니터링generating→complete상태 전환
-
결과 표시
ReportDetail컴포넌트로 분석 결과 표시
/login → loginApi() → 토큰 저장 → Redirect to /
/auth/kakao/callback?code=xxx
→ kakaoLoginApi(code)
→ 토큰 저장
→ Redirect to /
- 모바일: < 640px
- 태블릿: 640px ~ 1024px
- 데스크톱: > 1024px
Tailwind CSS로 모든 컴포넌트가 반응형 처리됨
docker build -t mindlog-frontend:latest .docker run -p 3000:3000 mindlog-frontend:latest원인: 토큰 갱신 실패
해결: .env.local의 NEXT_PUBLIC_API_URL 확인
원인: 이미지 변환 실패 (html-to-image)
해결: 브라우저 콘솔에서 SVG 렌더링 오류 확인
해결:
queryClient.invalidateQueries({ queryKey: ['sessions'] });-
새 브랜치 생성
git checkout -b feature/기능-이름
-
변경 후 커밋
git commit -m "feat: 기능 설명" -
푸시
git push origin feature/기능-이름
-
Pull Request 생성
Last Updated: 2026년 4월 26일