Skip to content

Commit eda5d4f

Browse files
authored
Revise README.md for project overview and details
Updated project introduction, goals, technology stack, contributions, problem-solving strategies, and project structure in README.md.
1 parent 1635f85 commit eda5d4f

1 file changed

Lines changed: 101 additions & 173 deletions

File tree

‎README.md‎

Lines changed: 101 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -1,175 +1,103 @@
1-
# FinVibe Frontend
1+
📌 프로젝트 소개
2+
3+
- FinVibe는 사용자가 가상 자산으로 실시간 시세 기반 투자 시뮬레이션을 수행할 수 있는 플랫폼입니다.
4+
- 사용자는 매수/매도 주문을 실행하고, 포트폴리오 평가금액 및 수익률 변화를 즉시 확인할 수 있습니다.
5+
- 이 프로젝트에서 저는 **금융 시뮬레이션 환경에서 데이터 정합성과 UI 안정성을 동시에 확보하는 프론트엔드 구조 설계**를 담당했습니다.
6+
---
7+
🎯 핵심 목표
8+
- 매수/매도 직후 포트폴리오 상태를 즉시 반영
9+
- 실시간 시세 변동에 따른 평가 금액 업데이트
10+
- 차트 데이터와 보유 자산 상태 동기화
11+
- UI 상태와 서버 상태 충돌 방지
12+
---
13+
🧱 기술 스택
14+
- **React**
15+
- 복잡한 투자 UI를 컴포넌트 단위로 모듈화
16+
- **TypeScript**
17+
- 금액/수량/수익률 계산 로직의 타입 안정성 확보
18+
- **TanStack Query**
19+
- 서버 상태 조회/캐싱/동기화 표준화
20+
- 매매 요청 이후 재동기화 전략 설계
21+
- 캐시 정책으로 중복 요청 감소
22+
- **Zustand**
23+
- 종목 선택, 필터, 모달, 인증, 실시간 시세 등 전역 상태 경량 관리
24+
- 서버 상태와 분리해 충돌 방지
25+
- **Lightweight Charts**
26+
- 번들 크기와 렌더링 성능을 고려한 시계열 차트 구성
27+
- **Axios Interceptor**
28+
- 토큰 주입/갱신(Refresh)/재시도 정책 일원화
29+
---
30+
🙋 기여 내용
31+
- 투자 시뮬레이션 화면 렌더링 구조 설계
32+
- 매매 후 포트폴리오 상태 동기화 구조 설계
33+
- React Query 기반 서버 상태 관리 표준화
34+
- Zustand 기반 전역 클라이언트 상태 구조 설계
35+
- 도메인별 API 계층 정리 및 에러 처리 일원화
36+
- 차트 렌더링 최적화
37+
- Storybook 기반 컴포넌트 개발 환경 구축
38+
---
39+
🛠 문제 해결
40+
1) 매매 후 포트폴리오 반영 지연 및 UI 불안정
41+
42+
| 문제 | 해결 | 결과 |
43+
| -------------------- | ------------------------ | ------------ |
44+
| 매수/매도 후 전체 리렌더링 | 영역 단위 상태 분리 | 부분 렌더링 구조 확보 |
45+
| 매매 반영 전 UI 깜빡임 | `keepPreviousData` 전략 적용 | 체감 지연 최소화 |
46+
| 시세 데이터와 포트폴리오 동기화 지연 | 재요청 정책 설계 | 데이터 정합성 확보 |
47+
48+
→ 매매가 빈번한 환경에서도 즉각적이고 안정적인 반영 구조를 구현
49+
50+
---
51+
2) 서버 상태와 UI 상태 혼재로 인한 충돌
52+
53+
| 문제 | 해결 | 결과 |
54+
| ---------------- | ------------------------ | ---------- |
55+
| 매매 후 중복 API 요청 | React Query 캐싱 전략 적용 | 네트워크 효율 개선 |
56+
| UI 상태와 서버 데이터 혼재 | Server / Client State 분리 | 상태 책임 명확화 |
57+
| 기능 확장 시 수정 범위 증가 | axios API 계층 일원화 | 유지보수성 향상 |
58+
59+
60+
→ 투자 시뮬레이션에서 중요한 데이터 일관성 강화
61+
62+
---
63+
64+
3) 차트 렌더링 부담
65+
66+
| 문제 | 해결 | 결과 |
67+
| ------------ | --------------------- | ----------- |
68+
| 무거운 차트 라이브러리 | lightweight-charts 도입 | 초기 로딩 부담 감소 |
69+
| 불필요한 리렌더링 | 메모이제이션 적용 | 렌더링 안정성 확보 |
70+
71+
72+
→ 시계열 데이터 환경에서 **성능과 가독성의 균형** 확보
73+
74+
---
75+
🏗 아키텍처
76+
본 프로젝트는 상태를 다음 3계층으로 분리한 하이브리드 구조를 사용합니다.
77+
- **Local UI State**: 컴포넌트 내부 UI 상태
78+
- **Global Client State (Zustand)**: 인증/사용자/실시간 시세 등 앱 전역 상태
79+
- **Server State (TanStack Query)**: REST API 데이터 조회·캐싱·동기화
80+
또한 도메인별 Axios 클라이언트로 API 계층을 분리해
81+
`baseURL`, 토큰 주입, 토큰 갱신(Refresh), 재시도 정책을 일관되게 관리했습니다.
82+
> **실시간 WebSocket 시세 데이터와 REST 거래 데이터를 분리 관리하여, 매매 이후 데이터 정합성과 UI 반응성을 동시에 확보했습니다.**
83+
84+
설계 의도
85+
- 매매 요청 후 Server State 재동기화
86+
- UI 상태 독립 관리로 충돌 방지
87+
- 단방향 데이터 흐름 유지
88+
- 낙관적 업데이트를 고려한 확장 가능한 구조
89+
기대 효과
90+
- 매매 반영 즉시성 확보
91+
- 포트폴리오 계산 정합성 유지
92+
- 예측 가능한 상태 전이 구조 확립
93+
---
94+
📊 다이어그램
95+
96+
1. 플로우차트
97+
<img width="600" height="1200" alt="핀바이브 플로우차트" src="https://github.com/user-attachments/assets/281346b7-4f2f-492d-9047-1e28b39b2bf4" />
98+
99+
100+
2. 시퀀스 다이어그램
101+
<img width="1200" height="631" alt="핀바이브 시퀀스다이어그램" src="https://github.com/user-attachments/assets/97d4d2e7-f382-47e2-a72a-65be263fd6c3" />
2102

3-
FinVibe 프로젝트의 프론트엔드 컴포넌트 라이브러리입니다.
4-
Figma 디자인 시스템을 기반으로 구축되었습니다.
5103

6-
## 기술 스택
7-
8-
- **React 19.2** - UI 라이브러리
9-
- **TypeScript** - 타입 안정성
10-
- **Vite 7** - 빌드 도구
11-
- **Tailwind CSS 3** - 유틸리티 우선 CSS 프레임워크
12-
- **Storybook 8** - 컴포넌트 개발 환경
13-
- **pnpm** - 패키지 매니저
14-
- **Figma** - 디자인 시스템 소스
15-
16-
## 시작하기
17-
18-
### 설치
19-
20-
```bash
21-
pnpm install
22-
```
23-
24-
### 개발 서버 실행
25-
26-
```bash
27-
pnpm dev
28-
```
29-
30-
### 스토리북 실행
31-
32-
```bash
33-
pnpm storybook
34-
```
35-
36-
### 빌드
37-
38-
```bash
39-
pnpm build
40-
```
41-
42-
## 프로젝트 구조
43-
44-
```
45-
src/
46-
├── components/ # 재사용 가능한 컴포넌트
47-
│ ├── Button/ # Button 컴포넌트
48-
│ │ ├── Button.tsx
49-
│ │ ├── Button.stories.tsx
50-
│ │ └── index.ts
51-
│ └── index.ts # 컴포넌트 export
52-
├── utils/ # 유틸리티 함수
53-
│ └── cn.ts # 클래스 이름 병합 유틸리티
54-
├── App.tsx # 메인 앱 컴포넌트
55-
├── main.tsx # 엔트리 포인트
56-
└── index.css # 글로벌 스타일 (Tailwind)
57-
```
58-
59-
## 컴포넌트
60-
61-
### Button
62-
63-
Figma 디자인 시스템에 기반한 재사용 가능한 버튼 컴포넌트입니다.
64-
65-
**디자인 소스:**
66-
67-
- Figma 파일: `FInVibe`
68-
- Small (s): Node ID `503-333`
69-
- Medium (m): Node ID `500-152`
70-
- Large (l): Node ID `540-161`
71-
72-
**Props:**
73-
74-
- `variant`: "primary" | "secondary"
75-
- `primary`: 검은색 배경, 흰색 텍스트 (활성 상태)
76-
- `secondary`: 흰색 배경, 회색 테두리, 검은색 텍스트 (비활성 상태)
77-
- `size`: "small" | "medium" | "large"
78-
- `small` (s): 작은 크기 - px-3 py-1.5, text-xs, min-h-28px (Figma: 503-333)
79-
- `medium` (m): 중간 크기 - px-[87px] py-3, text-sm, min-h-36px (Figma: 500-152, 기본값)
80-
- `large` (l): 큰 크기 - px-6 py-4, text-base, min-h-48px, 틸 색상 (Figma: 540-161)
81-
- `fullWidth`: boolean - 전체 너비 사용 여부
82-
- `loading`: boolean - 로딩 상태
83-
- `disabled`: boolean - 비활성화 상태
84-
- `leftIcon`: ReactNode - 왼쪽 아이콘
85-
- `rightIcon`: ReactNode - 오른쪽 아이콘
86-
87-
**디자인 스펙:**
88-
89-
- 폰트: Noto Sans KR Light, 14px
90-
- 패딩: 12px (상하) × 87px (좌우)
91-
- 보더 반경: 4px
92-
- Line height: 20px
93-
94-
**사용 예시:**
95-
96-
```tsx
97-
import { Button } from "./components";
98-
99-
function App() {
100-
return (
101-
<div>
102-
<Button variant="primary">취소</Button>
103-
104-
<Button variant="secondary">취소</Button>
105-
106-
{/* 크기 변형 */}
107-
<Button size="small">Small</Button>
108-
<Button size="medium">Medium</Button>
109-
<Button size="large">Large</Button>
110-
111-
<Button loading>로딩 중...</Button>
112-
113-
<Button leftIcon={<span>✓</span>}>확인</Button>
114-
</div>
115-
);
116-
}
117-
```
118-
119-
## 스타일링
120-
121-
이 프로젝트는 Tailwind CSS를 사용합니다. 커스텀 CSS 파일 대신 Tailwind 유틸리티 클래스를 사용하세요.
122-
123-
### cn 유틸리티
124-
125-
`clsx`와 `tailwind-merge`를 결합한 유틸리티 함수로, Tailwind 클래스 충돌을 해결합니다.
126-
127-
```tsx
128-
import { cn } from "./utils/cn";
129-
130-
const className = cn(
131-
"base-classes",
132-
condition && "conditional-classes",
133-
"override-classes"
134-
);
135-
```
136-
137-
## 스토리북
138-
139-
모든 컴포넌트는 Storybook 스토리를 포함해야 합니다.
140-
141-
스토리 파일은 컴포넌트와 같은 디렉토리에 위치합니다:
142-
143-
- `ComponentName.tsx` - 컴포넌트
144-
- `ComponentName.stories.tsx` - 스토리북 스토리
145-
146-
## 개발 가이드
147-
148-
### 새 컴포넌트 추가
149-
150-
1. `src/components/ComponentName/` 디렉토리 생성
151-
2. `ComponentName.tsx` 파일 생성 (Tailwind CSS 사용)
152-
3. `ComponentName.stories.tsx` 파일 생성
153-
4. `index.ts`에서 export
154-
5. `src/components/index.ts`에 추가
155-
156-
### 코드 스타일
157-
158-
- TypeScript 사용
159-
- Tailwind CSS 유틸리티 클래스 사용
160-
- 컴포넌트는 재사용 가능하게 설계
161-
- Props는 명확하게 타입 정의
162-
- JSDoc 주석으로 문서화
163-
164-
## 스크립트
165-
166-
- `pnpm dev` - 개발 서버 실행
167-
- `pnpm build` - 프로덕션 빌드
168-
- `pnpm preview` - 빌드 미리보기
169-
- `pnpm lint` - ESLint 실행
170-
- `pnpm storybook` - 스토리북 개발 서버
171-
- `pnpm build-storybook` - 스토리북 빌드
172-
173-
## 라이선스
174-
175-
Private

0 commit comments

Comments
 (0)