Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d57cf88
[Refactor] 회원가입, 로그인 로직 수정
cccwon2 Nov 6, 2024
e770fb6
[Feat] zod, react-query 추가
cccwon2 Nov 6, 2024
686528d
[Chore] react-hook-form zod 스키마를 연결해주는 resolver 추가
cccwon2 Nov 6, 2024
e908572
[Refactor] react query 적용하는 중
cccwon2 Nov 7, 2024
f0142af
[Refactor] 리팩토링 중
cccwon2 Nov 7, 2024
3411baf
[Refactor] middleware, 로그인 및 회원가입 페이지 폴더 변경
cccwon2 Nov 10, 2024
e7952ef
[Refactor] 게시글 관련 리팩토링
cccwon2 Nov 10, 2024
528adce
[Refactor] comment 관련 컴포넌트에 useComment 훅 적용
cccwon2 Nov 11, 2024
ee89cce
[Refactor] ItemDetailSection 에 useProduct 훅 적용
cccwon2 Nov 11, 2024
c7c3eb5
[Refactor] 나머지 부분 리팩토링
cccwon2 Nov 11, 2024
8306df7
[Refactor] auth 관련 수정
cccwon2 Nov 12, 2024
16fd666
[Refactor] auth 관련 파일 및 middleware 수정
cccwon2 Nov 12, 2024
643b09f
[Fix] 루트 경로에 남아있는 pages 폴더 삭제
cccwon2 Nov 12, 2024
aa3c9ba
[Fix] 로그인, 로그아웃 버그 수정
cccwon2 Nov 12, 2024
929d80c
[Docs] README.md 수정
cccwon2 Nov 12, 2024
d2f0c67
[Chore] header logout 관련 에러 수정
cccwon2 Nov 12, 2024
9d9b52e
[Refactor] 게시글 목록 수정
cccwon2 Nov 12, 2024
4a68388
[Feat] comments, products 리스트, 상세 API 추가
cccwon2 Nov 13, 2024
4663763
[Refactor] Comment 관련 수정
cccwon2 Nov 13, 2024
834238a
[Refactor] login 페이지 수정
cccwon2 Nov 13, 2024
e65bbc4
[Refactor] Signup 페이지 수정
cccwon2 Nov 13, 2024
810049e
[Refactor] 상품 페이지 관련 수정
cccwon2 Nov 13, 2024
e643b44
[Chore] 사용하지 않는 import 제거
cccwon2 Nov 13, 2024
06e9573
[Fix] 생략된 interface 추가 및 적용
cccwon2 Nov 13, 2024
cdccf91
[Chore] 상품 등록하기 버튼 추가
cccwon2 Nov 13, 2024
c610acb
[Feat] 개발 모드에서 react-query-devtools 적용
cccwon2 Nov 13, 2024
ece1af2
[Feat] useUser 훅 추가, 새로고침시 refreshToken 으로 사용자 정보 갱신
cccwon2 Nov 13, 2024
761bd69
[Fix] 게시글 좋아요 버그 수정, CSS 수정
cccwon2 Nov 13, 2024
9aaf4f7
[Refactor] 이미지 프록시 관련 및 API 구조 변경
cccwon2 Nov 14, 2024
36cd949
[Feat] 상품 및 게시글 수정/삭제 기능 추가
cccwon2 Nov 14, 2024
9a2236a
[Feat] 상품 및 게시글 댓글 수정/삭제 기능 추가
cccwon2 Nov 14, 2024
018fbf0
[Chore] 필요없는 라이브러리 제거 및 README.md 수정
cccwon2 Nov 14, 2024
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
183 changes: 132 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,78 +1,159 @@
# FE9 Weekly Mission
# FE9 Sprint Mission

이 프로젝트는 [Next.js](https://nextjs.org)를 기반으로 만들어진 주간 미션 프로젝트입니다.
## 소개

## 배포 사이트
이 프로젝트는 Next.js Page Router 기반의 커뮤니티 및 중고마켓 플랫폼입니다. 사용자들은 게시글을 작성하고, 상품을 등록하며, 댓글과 좋아요 기능을 통해 상호작용할 수 있습니다.

프로젝트는 다음 URL에서 확인할 수 있습니다: [https://next-panda-market.vercel.app](https://next-panda-market.vercel.app)
## 주요 기능

## 시작하기
### 커뮤니티

먼저, 개발 서버를 실행하세요:
- 게시글 CRUD
- 댓글 시스템
- 좋아요 기능
- 베스트 게시글
- 실시간 검색
- 정렬 기능 (최신순/인기순)

### 중고마켓

- 상품 등록/수정/삭제
- 상품 문의
- 찜하기 기능
- 베스트 상품
- 검색 및 정렬

## 기술 스택

### 핵심 의존성

[![Next.js](https://img.shields.io/badge/Next.js-14.2.12-black?logo=next.js)](https://nextjs.org/)
[![React](https://img.shields.io/badge/React-18-blue?logo=react)](https://reactjs.org/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript)](https://www.typescriptlang.org/)
[![TailwindCSS](https://img.shields.io/badge/TailwindCSS-3.4.13-38B2AC?logo=tailwind-css)](https://tailwindcss.com/)

### 상태 관리 & API

[![React Query](https://img.shields.io/badge/@tanstack/react--query-5.59.20-FF4154?logo=react-query)](https://tanstack.com/query)
[![Jotai](https://img.shields.io/badge/Jotai-2.10.0-black)](https://jotai.org/)
[![Axios](https://img.shields.io/badge/Axios-1.7.7-5A29E4?logo=axios)](https://axios-http.com/)

### 폼 & 유효성 검증

[![React Hook Form](https://img.shields.io/badge/React%20Hook%20Form-7.53.1-EC5990)](https://react-hook-form.com/)
[![HookForm Resolvers](https://img.shields.io/badge/@hookform/resolvers-3.9.1-EC5990)](https://github.com/react-hook-form/resolvers)
[![Zod](https://img.shields.io/badge/Zod-3.23.8-3068B7)](https://zod.dev/)

### UI/UX

[![React Hot Toast](https://img.shields.io/badge/React%20Hot%20Toast-2.4.1-FF4444)](https://react-hot-toast.com/)
[![React Spinners](https://img.shields.io/badge/React%20Spinners-0.14.1-36D7B7)](https://www.davidhu.io/react-spinners/)
[![Tailwind Merge](https://img.shields.io/badge/Tailwind%20Merge-2.5.2-38B2AC)](https://github.com/dcastil/tailwind-merge)

### 유틸리티

[![Sharp](https://img.shields.io/badge/Sharp-0.33.5-99CC00)](https://sharp.pixelplumbing.com/)
[![date-fns](https://img.shields.io/badge/date--fns-4.1.0-yellow)](https://date-fns.org/)
[![Form Data](https://img.shields.io/badge/Form%20Data-4.0.0-green)](https://github.com/form-data/form-data)
[![Formidable](https://img.shields.io/badge/Formidable-3.5.1-orange)](https://github.com/node-formidable/formidable)

## 프로젝트 설정

### 환경 설정

1. 의존성 설치:

```bash
npm install
```

2. 개발 서버 실행:

```bash
npm run dev
# 또는
yarn dev
# 또는
pnpm dev
```

브라우저에서 [http://localhost:3000](http://localhost:3000)을 열어 결과를 확인하세요.
3. 프로덕션 빌드:

```bash
npm run build
```

4. 프로덕션 서버 실행:

```bash
npm run start
```

## 사용된 기술 스택
### 주요 설정 파일

- [Next.js](https://nextjs.org/) - React 기반의 웹 애플리케이션 프레임워크
- [React](https://reactjs.org/) - UI 구축을 위한 라이브러리
- [TypeScript](https://www.typescriptlang.org/) - JavaScript의 정적 타입 검사 확장
- [Tailwind CSS](https://tailwindcss.com/) - 유틸리티-퍼스트 CSS 프레임워크
- [Jotai](https://jotai.org/) - React 상태 관리 라이브러리
#### TailwindCSS (tailwind.config.ts)

## 주요 의존성
- 커스텀 색상 및 스페이싱
- Pretendard 폰트 설정
- 반응형 디자인 지원

- next: 14.2.12
- react: ^18
- react-dom: ^18
- axios: ^1.7.7
- date-fns: ^4.1.0
- jotai: ^2.10.0
- js-cookie: ^3.0.5
- react-hook-form: ^7.53.0
- react-router-dom: ^6.26.2
- react-spinners: ^0.14.1
- sharp: ^0.33.5
- tailwind-merge: ^2.5.2
#### Next.js (next.config.mjs)

## 개발 의존성
- 이미지 최적화 설정
- SVG 파일 처리
- Node.js 모듈 설정

#### TypeScript (tsconfig.json)

- 엄격한 타입 검사
- 절대 경로 설정
- Next.js 타입 지원

### 미들웨어

- 인증 보호
- API 라우트 보호
- 이미지 프록시 처리

## 폴더 구조

```
src/
├── components/
│ ├── Layout/
│ ├── UI/
│ │ ├── community/
│ │ ├── item/
│ │ └── comment/
├── hooks/
├── pages/
├── store/
├── types/
└── utils/
```

- typescript: ^5
- eslint: ^8
- eslint-config-next: 14.2.12
- autoprefixer: ^10.4.20
- postcss: ^8.4.47
- tailwindcss: ^3.4.13
## 개발 가이드

## 스크립트
### 컴포넌트 작성

- `npm run dev`: 개발 서버 실행
- `npm run build`: 프로덕션 빌드
- `npm run start`: 프로덕션 모드로 서버 실행
- `npm run lint`: 린트 검사 실행
- `npm run clean`: 빌드 폴더 삭제
- 재사용 가능한 UI 컴포넌트는 `components/UI` 폴더에 위치
- 레이아웃 관련 컴포넌트는 `components/Layout` 폴더에 위치
- Props 타입은 명시적으로 정의

## Tailwind CSS 설정
### 상태 관리

Tailwind CSS는 커스텀 테마를 지원하며, 설정은 `tailwind.config.ts` 파일에서 관리됩니다.
- 전역 상태는 Jotai 사용
- 서버 상태는 React Query 사용
- 폼 상태는 React Hook Form 사용

## Webpack 설정
### 스타일링

SVG 파일 처리를 위해 `@svgr/webpack`을 사용하며, 특정 Node.js 모듈(`fs`, `path`, `os`)은 브라우저에서 비활성화되어 있습니다.
- TailwindCSS 클래스 사용
- 반응형 디자인 적용
- tailwind-merge로 클래스 충돌 방지

## 더 알아보기
### 참고 문서

- [Next.js 문서](https://nextjs.org/docs) - 기능과 API에 대해 알아보세요.
- [Next.js 학습](https://nextjs.org/learn) - 대화형 튜토리얼 체험.
- [Next.js 문서](https://nextjs.org/docs)
- [React 문서](https://reactjs.org/)
- [TailwindCSS 문서](https://tailwindcss.com/)

## 배포

Next.js 앱을 배포하는 가장 쉬운 방법은 [Vercel 플랫폼](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme)을 사용하는 것입니다.
이 프로젝트는 [Vercel Platform](https://vercel.com)을 통해 쉽게 배포할 수 있습니다.
83 changes: 64 additions & 19 deletions middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,81 @@ import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { isValidImageUrl } from "@/utils/imageUtils"; // 이미지 확장자 검증 함수 가져오기

// imageProxy 관련 로직을 별도 함수로 분리하여 가독성 향상
const handleImageProxy = (url: URL) => {
const imageUrl = url.searchParams.get("url");

if (!imageUrl) {
return NextResponse.json({ error: "이미지 URL이 필요합니다." }, { status: 400 });
}

// 로컬 이미지 경로인 경우 프록시 처리하지 않음
if (imageUrl.startsWith("/images/")) {
return NextResponse.next();
}

if (!isValidImageUrl(imageUrl)) {
return NextResponse.json({ error: "허용되지 않은 파일 형식입니다." }, { status: 400 });
}

return NextResponse.next();
};

// 미들웨어 함수
export function middleware(request: NextRequest) {
export const middleware = (request: NextRequest) => {
const url = request.nextUrl.clone();

// /api/imageProxy 경로에 대한 요청만 처리
// 이미지 프록시 요청 처리
if (url.pathname.startsWith("/api/imageProxy")) {
const imageUrl = url.searchParams.get("url");

// 이미지 URL이 없는 경우 에러 반환
if (!imageUrl) {
return NextResponse.json(
{ error: "이미지 URL이 필요합니다." },
{ status: 400 }
);
return handleImageProxy(url);
}

const accessToken = request.cookies.get("accessToken");
const { pathname } = request.nextUrl;

// 인증이 필요한 페이지 목록 (비공개 페이지)
const privatePages = ["/addArticle", "/addItem"];
Copy link
Collaborator

Choose a reason for hiding this comment

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

미들웨어로 인가를 처리하셨군요 👍

const isPrivatePage = privatePages.some((page) => pathname === page);
const isAuthPage = ["/login", "/signup"].includes(pathname);

// API 라우트에 대한 처리
if (pathname.startsWith("/api")) {
// /api/auth로 시작하는 경로는 모두 통과
if (pathname.startsWith("/api/auth")) {
return NextResponse.next();
}

// refreshToken 엔드포인트는 별도 처리
if (pathname === "/api/auth/refreshToken") {
return NextResponse.next();
}

// isValidImageUrl 함수 사용하여 확장자 검증
if (!isValidImageUrl(imageUrl)) {
return NextResponse.json(
{ error: "허용되지 않은 파일 형식입니다." },
{ status: 400 }
);
// 토큰이 없는 경우 401 응답
if (!accessToken) {
return NextResponse.json({ message: "인증이 필요합니다." }, { status: 401 });
}
}

// 다른 요청에 대해 계속 처리
// 로그인된 사용자가 로그인/회원가입 페이지 접근 시 홈으로 리다이렉트
if (accessToken && isAuthPage) {
return NextResponse.redirect(new URL("/", request.url));
}

// 비공개 페이지에 대한 접근 제어
if (!accessToken && isPrivatePage) {
return NextResponse.redirect(new URL("/login", request.url));
}

// 다른 모든 요청 허용
return NextResponse.next();
}
};

// 미들웨어가 적용될 경로 설정
export const config = {
matcher: "/api/imageProxy",
matcher: [
// API 라우트
"/api/:path*",
// 정적 파일을 제외한 모든 경로
"/((?!_next|public|favicon.ico).*)",
],
};
Loading
Loading