Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
71080cd
docs: 과제 제출을 위한 README 수정
kimzeze Nov 10, 2025
8d63639
style: Prettier 포매팅 설정 추가
kimzeze Nov 11, 2025
ea6a706
refactor: HTML 템플릿을 별도 파일로 분리
kimzeze Nov 11, 2025
3d6faff
refactor: 재사용 가능한 컴포넌트 구조 추가
kimzeze Nov 11, 2025
9723cb8
refactor: 페이지 레벨 컴포넌트 구조 추가
kimzeze Nov 11, 2025
6939087
refactor: main.js를 컴포넌트 기반으로 리팩토링
kimzeze Nov 11, 2025
ce352d7
docs: AI를 활용해 과제 명세에 대한 가이드라인 문서 생성
kimzeze Nov 11, 2025
5b18d20
docs: 커밋 가이드 md파일 작성
kimzeze Nov 11, 2025
6c99d31
docs: 과제 명세에 대한 가이드라인 문서 재작성
kimzeze Nov 11, 2025
f29e415
docs: 업데이트된 문서 구조 및 Observer 패턴, Router, Store, Lifecycle 시스템 추가
kimzeze Nov 11, 2025
37eb525
refactor: 404 Not Found 페이지 컴포넌트 추가
kimzeze Nov 11, 2025
353e0d4
feat: Observer 패턴 구현
kimzeze Nov 11, 2025
1474eb1
feat: Router 시스템 구현
kimzeze Nov 11, 2025
fa18100
feat: localStorage 래퍼 유틸리티 구현
kimzeze Nov 11, 2025
57516b2
feat: Store 상태 관리 시스템 구현
kimzeze Nov 11, 2025
3f7ad18
refactor: Router와 Store를 main.js에 연결
kimzeze Nov 11, 2025
8680fd6
fix: 템플릿 문자열을 사용하여 상품 개수 표시 수정
kimzeze Nov 11, 2025
cc1c39d
feat: 생명주기 시스템 구현 (mount/watch/unmount 훅)
kimzeze Nov 13, 2025
2414b32
fix: pagination.total을 사용하여 전체 상품 개수 표시
kimzeze Nov 13, 2025
1397735
feat: 검색 기능 구현
kimzeze Nov 13, 2025
7780922
fix: lifecycle watch 무한 루프 버그 수정
kimzeze Nov 13, 2025
d3433f7
feat: 카테고리 목록 로딩 및 표시 기능 구현
kimzeze Nov 13, 2025
418556a
feat: 상품 개수 및 정렬 필터 기능 구현
kimzeze Nov 13, 2025
a29a40f
feat: 카테고리 필터 UI 및 breadcrumb 구현
kimzeze Nov 13, 2025
7551111
feat: 카테고리 필터 이벤트 핸들러 추가
kimzeze Nov 13, 2025
20121f6
fix: ProductList에 brand 표시 및 productId 수정
kimzeze Nov 13, 2025
2c5052b
feat: 장바구니 담기 버튼에 상품 데이터 추가
kimzeze Nov 13, 2025
89ee385
feat: 장바구니 개수 뱃지 표시 기능 추가
kimzeze Nov 13, 2025
7d5fdb7
feat: 토스트 알림 시스템 및 장바구니 담기 기능 구현
kimzeze Nov 13, 2025
760706b
feat: 장바구니 모달 컴포넌트 생성
kimzeze Nov 13, 2025
e7aebc5
feat: 장바구니 모달 관리 유틸 함수 추가
kimzeze Nov 13, 2025
87d28ab
feat: 장바구니 모달 열기 및 닫기 기능 구현
kimzeze Nov 13, 2025
594e124
feat: 장바구니 모달에 store 구독 시스템 추가
kimzeze Nov 13, 2025
b921d95
feat: 장바구니 모달 내 상품 관리 기능 구현
kimzeze Nov 13, 2025
95e6dd1
feat: 장바구니 체크박스 선택 및 일괄 삭제 기능 구현
kimzeze Nov 13, 2025
7b21cb6
feat: 상세 페이지 수량 조절 및 장바구니 담기 구현
kimzeze Nov 13, 2025
4c752db
feat: 관련 상품 기능 구현
kimzeze Nov 13, 2025
80ccb1e
feat: 상세 페이지 브레드크럼 네비게이션 구현
kimzeze Nov 13, 2025
fb67e88
refactor: 장바구니 모달 DOM 구조 개선
kimzeze Nov 13, 2025
a7f39c8
refactor: DetailPage를 독립적인 레이아웃으로 변경
kimzeze Nov 13, 2025
6269dc5
refactor: localStorage 키를 cart에서 shopping_cart로 변경
kimzeze Nov 13, 2025
ee0ac86
fix: 404 페이지를 template.js 구조에 맞게 수정
kimzeze Nov 13, 2025
04c63bf
feat: IntersectionObserver 기반 무한 스크롤 유틸 구현
kimzeze Nov 13, 2025
b0b45e1
feat: getProducts API에 skip 파라미터 지원 추가
kimzeze Nov 13, 2025
c331666
feat: HomePage에 무한 스크롤 기능 구현
kimzeze Nov 13, 2025
864fa60
fix: 토스트 닫기 버튼에 ID 추가
kimzeze Nov 13, 2025
5c10f57
fix: 404 페이지에 헤더와 푸터 추가
kimzeze Nov 13, 2025
e8d07a7
fix: 토스트 알림 개선
kimzeze Nov 13, 2025
f0c4442
refactor: 토스트에서 미사용 애니메이션 클래스 제거
kimzeze Nov 13, 2025
ba4546a
feat: 상품 목록으로 돌아가기 버튼 개선
kimzeze Nov 13, 2025
72ddce5
feat: 장바구니 선택 상태 localStorage 저장 기능 추가
kimzeze Nov 13, 2025
88b6d40
feat: 무한 스크롤 로딩 시 스켈레톤 UI 추가
kimzeze Nov 13, 2025
07a3139
feat: githubAction을 이용한 배포세팅
kimzeze Nov 13, 2025
2da5b6b
feat: 404 페이지 수정
kimzeze Nov 13, 2025
e285c4b
feat: 상품 로드 실패 시 에러 처리 및 UI 개선
kimzeze Nov 13, 2025
b33b6ce
feat: 상품 상세 페이지에 뒤로가기 버튼 기능 추가
kimzeze Nov 13, 2025
564c204
chore: pnpm action 버전 수정
kimzeze Nov 13, 2025
96606ad
chore: packageManager 필드 제거
kimzeze Nov 13, 2025
cd1bb59
chore: .gitignore에 docs/ 추가 및 문서 파일 삭제
kimzeze Nov 13, 2025
9c52734
chore: Vite config 수정하여 프로덕션 모드에서만 base path 적용
kimzeze Nov 13, 2025
2275f8a
fix: Header 위치 수정
kimzeze Nov 13, 2025
973705f
chore: 배포를 위한 package.json 수정
kimzeze Nov 13, 2025
3ba1940
chore: CI/CD를 위해 package.json 수정
kimzeze Nov 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## [4팀 김도현] Chapter2-1. 프레임워크 없이 SPA 만들기

## 과제 체크포인트

### 배포 링크
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Deploy to GitHub Pages

on:
push: # push trigger
branches:
- main

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: true

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "pnpm"

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build

- name: Setup Pages
uses: actions/configure-pages@v4

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: "./dist"

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ dist-ssr
/playwright-report/
coverage
.coverage

# Documentation (개인 작업용)
docs/
4 changes: 3 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
"tabWidth": 2,
"semi": true,
"singleQuote": false,
"printWidth": 120
"printWidth": 120,
"embeddedLanguageFormatting": "auto",
"htmlWhitespaceSensitivity": "css"
}
275 changes: 275 additions & 0 deletions COMMIT_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
# 커밋 가이드

## 과제 목표
- 프레임워크 없이 SPA(Single Page Application) 구현
- React가 해결하고자 하는 문제를 이해하고 직접 해결
- 라우팅, 상태관리, 컴포넌트 구조를 vanilla JS로 구현
- 테스트 코드 통과 및 GitHub Pages 배포

## 커밋 컨벤션

### 커밋 메시지 형식
```
<타입>: <제목>

<본문> (선택사항)

<꼬리말> (선택사항)
```

### 커밋 타입

| 타입 | 설명 | 예시 |
|------|------|------|
| `feat` | 새로운 기능 추가 | feat: 상품 목록 무한 스크롤 구현 |
| `refactor` | 코드 리팩토링 (기능 변경 없이 구조 개선) | refactor: 컴포넌트 기반 아키텍처로 전환 |
| `style` | 코드 포매팅, 세미콜론 누락 등 | style: Prettier 설정 추가 |
| `fix` | 버그 수정 | fix: 장바구니 수량 계산 오류 수정 |
| `chore` | 빌드 설정, 패키지 매니저 설정 등 | chore: MSW 설정 및 mock 데이터 추가 |
| `docs` | 문서 수정 | docs: README에 프로젝트 실행 방법 추가 |
| `test` | 테스트 코드 추가/수정 | test: 상품 목록 e2e 테스트 추가 |
| `design` | UI/UX 디자인 변경 | design: 상품 카드 레이아웃 개선 |

## 현재 변경사항 커밋 제안

### 방안 1: 상세하게 분리 (권장)

```bash
# 1. 코드 포매팅 설정
git add .prettierrc
git commit -m "style: Prettier 포매팅 설정 추가

- embeddedLanguageFormatting: auto 추가
- htmlWhitespaceSensitivity: css 추가
- HTML 템플릿 리터럴 포매팅 개선"

# 2. 템플릿 분리
git add src/template.js
git commit -m "refactor: HTML 템플릿을 별도 파일로 분리

- main.js에 있던 대량의 HTML 템플릿 코드를 template.js로 이동
- 상품목록, 장바구니, 상세페이지 등 모든 템플릿 포함
- 코드 가독성 및 유지보수성 향상"

# 3. 컴포넌트 구조 추가
git add src/components/
git commit -m "refactor: 재사용 가능한 컴포넌트 구조 추가

컴포넌트 목록:
- Header: 헤더 및 장바구니 아이콘
- Footer: 푸터 영역
- SearchForm: 검색 및 필터 폼
- ProductList: 상품 목록 그리드
- ProductDetail: 상품 상세 정보

각 컴포넌트는 독립적으로 재사용 가능하도록 구현"

# 4. 페이지 구조 추가
git add src/pages/
git commit -m "refactor: 페이지 레벨 컴포넌트 구조 추가

페이지 목록:
- PageLayout: 공통 레이아웃 (Header + Footer)
- HomePage: 상품 목록 페이지
- DetailPage: 상품 상세 페이지

SPA 라우팅을 위한 페이지 단위 분리"

# 5. 메인 파일 리팩토링
git add src/main.js
git commit -m "refactor: main.js를 컴포넌트 기반으로 리팩토링

- 템플릿 코드 제거
- 페이지 및 컴포넌트 import로 대체
- 코드 라인 수 대폭 감소 (1100+ → 40 lines)
- 전체 코드 구조 개선"
```

### 방안 2: 간단하게 분리

```bash
# 1. 코드 포매팅 설정
git add .prettierrc
git commit -m "style: Prettier 포매팅 설정 추가"

# 2. 전체 리팩토링
git add src/
git commit -m "refactor: 컴포넌트 기반 아키텍처로 전환

변경사항:
- HTML 템플릿을 template.js로 분리
- 재사용 가능한 컴포넌트 구조 추가 (Header, Footer, SearchForm, ProductList, ProductDetail)
- 페이지 레벨 컴포넌트 추가 (PageLayout, HomePage, DetailPage)
- main.js 간결화 및 모듈화

목적:
- 코드 가독성 및 유지보수성 향상
- SPA 구현을 위한 구조적 기반 마련"
```

## 이후 개발 시 커밋 가이드

### 기능 개발 단계별 커밋 예시

#### 1단계: 라우팅 시스템
```bash
feat: 클라이언트 사이드 라우팅 시스템 구현

- History API를 이용한 SPA 라우팅
- popstate 이벤트 핸들링
- 동적 페이지 렌더링
```

#### 2단계: 상태 관리
```bash
feat: 전역 상태 관리 시스템 구현

- Observer 패턴 기반 상태 관리
- 상태 변경 시 자동 리렌더링
- 장바구니 상태 관리
```

#### 3단계: 상품 목록 기능
```bash
feat: 상품 목록 조회 및 필터링 기능 구현

- API 연동 및 상품 데이터 로드
- 검색, 카테고리 필터링
- 정렬 기능 (가격순, 이름순)
```

#### 4단계: 무한 스크롤
```bash
feat: 상품 목록 무한 스크롤 구현

- Intersection Observer API 활용
- 페이지네이션 로직
- 로딩 스켈레톤 UI
```

#### 5단계: 장바구니 기능
```bash
feat: 장바구니 CRUD 기능 구현

- 상품 추가/삭제
- 수량 조절
- 전체 선택/삭제
- LocalStorage 연동
```

#### 6단계: 상품 상세
```bash
feat: 상품 상세 페이지 구현

- 동적 라우팅 (/product/:id)
- 상품 상세 정보 표시
- 관련 상품 추천
```

#### 7단계: URL 상태 동기화
```bash
feat: URL 쿼리 파라미터 상태 동기화

- 검색어, 필터, 정렬 조건 URL 반영
- 새로고침 시 상태 복원
- 브라우저 히스토리 관리
```

#### 8단계: 에러 처리
```bash
feat: 404 페이지 및 에러 처리 구현

- 존재하지 않는 경로 처리
- API 에러 핸들링
- 사용자 피드백 (토스트)
```

### 리팩토링 커밋 예시

```bash
refactor: 이벤트 핸들러 로직 분리

- 컴포넌트에서 이벤트 로직 추출
- 재사용 가능한 이벤트 핸들러 함수 작성
```

```bash
refactor: API 호출 로직 유틸리티로 분리

- 중복된 fetch 로직 제거
- 에러 처리 일관성 확보
```

```bash
refactor: 상태 업데이트 로직 최적화

- 불필요한 리렌더링 방지
- 성능 개선
```

## 커밋 작성 원칙

### DO ✅

1. **의미 있는 단위로 커밋**
- 하나의 커밋은 하나의 목적
- 독립적으로 이해 가능한 변경사항

2. **구체적인 제목 작성**
```
❌ feat: 기능 추가
✅ feat: 상품 검색 기능 구현
```

3. **Why를 설명하는 본문 작성**
```
feat: Observer 패턴으로 상태 관리 구현

React의 useState와 유사한 반응형 상태 관리를 위해
Observer 패턴을 구현했습니다.
상태 변경 시 자동으로 구독자들에게 알림을 보내
UI가 자동으로 업데이트됩니다.
```

4. **테스트와 함께 커밋**
```
feat: 무한 스크롤 구현

- Intersection Observer 활용
- 스크롤 위치 감지 및 다음 페이지 로드
- e2e 테스트 통과 확인
```

### DON'T ❌

1. **너무 큰 커밋 지양**
- 여러 기능을 한 번에 커밋하지 않기
- 리팩토링과 기능 추가를 섞지 않기

2. **모호한 커밋 메시지**
```
❌ fix: 수정
❌ update: 업데이트
❌ refactor: 코드 정리
```

3. **WIP(Work In Progress) 커밋 남기지 않기**
- 개발 중간에 임시 커밋하지 않기
- 완성된 단위로 커밋

4. **포매팅과 로직 변경을 함께 커밋**
- 포매팅은 별도 커밋으로 분리

## 과제 제출 시 체크리스트

- [ ] 각 커밋이 독립적으로 의미를 가지는가?
- [ ] 커밋 메시지가 변경 내용을 명확히 설명하는가?
- [ ] feat/refactor/fix 등 타입이 올바르게 사용되었는가?
- [ ] 모든 테스트가 통과하는가?
- [ ] 배포가 정상적으로 되는가?

## 참고 자료

- [Conventional Commits](https://www.conventionalcommits.org/ko/v1.0.0/)
- [좋은 git commit 메시지를 위한 영어 사전](https://blog.ull.im/engineering/2019/03/10/logs-on-git.html)
- [커밋 메시지 가이드](https://github.com/RomuloOliveira/commit-messages-guide/blob/master/README_ko-KR.md)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"dev": "vite",
"dev:hash": "vite --open ./index.hash.html",
"build": "vite build",
"build": "vite build && cp dist/index.html dist/404.html",
"lint:fix": "eslint --fix",
"prettier:write": "prettier --write ./src",
"preview": "vite preview",
Expand Down
11 changes: 9 additions & 2 deletions src/api/productApi.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
// 상품 목록 조회
export async function getProducts(params = {}) {
const { limit = 20, search = "", category1 = "", category2 = "", sort = "price_asc" } = params;
const page = params.current ?? params.page ?? 1;
const { limit = 20, skip, search = "", category1 = "", category2 = "", sort = "price_asc" } = params;

// skip이 있으면 page로 변환, 없으면 기존 방식 사용
let page;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7. 페이지네이션 파라미터 변환 로직

skiplimit이 존재할 경우 이를 page로 변환하는 부분은 무한 스크롤 API 호출에 적합합니다.

  • 추가 요구사항으로 offset 기반 페이징이 독립적으로 확장될 경우, API 파라미터 매핑을 별도 모듈이나 서비스로 분리하면 유지보수에 도움이 됩니다.

if (skip !== undefined) {
page = Math.floor(skip / limit) + 1;
} else {
page = params.current ?? params.page ?? 1;
}

const searchParams = new URLSearchParams({
page: page.toString(),
Expand Down
Loading