481 lines
18 KiB
Markdown
481 lines
18 KiB
Markdown
# 게시물(Post) 관리 프로그램 아키텍처 문서
|
|
|
|
## 개요
|
|
|
|
이 문서는 게시물(Post) 관리 프로그램의 아키텍처와 소스 흐름에 대한 상세 설명입니다. 게시물 관리 기능은 게시판에 게시물을 등록, 조회, 수정, 삭제하는 기능을 제공하며, 다양한 유형의 게시물(일반, 이미지, 동영상, 공지사항 등)을 지원합니다.
|
|
|
|
## 기술 스택
|
|
|
|
- **프레임워크**: Next.js (App Router)
|
|
- **상태 관리**: React Query, Zustand(useMenuStore, useUserStore)
|
|
- **UI 컴포넌트**: @common/components
|
|
- **테이블 관리**: TanStack Table
|
|
- **폼 관리**: React Hook Form, Zod
|
|
- **API 통신**: Axios
|
|
- **파일 업로드**: 커스텀 파일 업로더 컴포넌트
|
|
|
|
## 디렉토리 구조
|
|
|
|
```
|
|
frontend/
|
|
├── apps/
|
|
│ └── cs/
|
|
│ ├── app/
|
|
│ │ └── (with-base-layout)/
|
|
│ │ └── bbs/
|
|
│ │ └── (post)/ # 게시물 관련 페이지
|
|
│ ├── src/
|
|
│ │ ├── entities/
|
|
│ │ │ ├── post/
|
|
│ │ │ │ ├── api/
|
|
│ │ │ │ │ └── post-service.ts # 게시물 API 호출 함수
|
|
│ │ │ │ └── model/
|
|
│ │ │ │ └── post-interface.ts # 게시물 인터페이스 정의
|
|
│ │ │ └── posting/
|
|
│ │ │ ├── api/
|
|
│ │ │ │ └── posting-service.ts # 게시 관련 API 호출 함수
|
|
│ │ │ ├── model/
|
|
│ │ │ │ └── posting-interface.ts # 게시 관련 인터페이스 정의
|
|
│ │ │ └── ui/
|
|
│ │ │ └── posting-dialog.tsx # 게시 관련 다이얼로그 컴포넌트
|
|
│ │ ├── pages/
|
|
│ │ │ └── (post)/
|
|
│ │ │ ├── image/
|
|
│ │ │ │ └── ui/
|
|
│ │ │ │ └── image-post.tsx # 이미지 게시물 컴포넌트
|
|
│ │ │ ├── movie/
|
|
│ │ │ │ └── ui/
|
|
│ │ │ │ └── movie-post.tsx # 동영상 게시물 컴포넌트
|
|
│ │ │ ├── normal/
|
|
│ │ │ │ └── ui/
|
|
│ │ │ │ └── normal-post.tsx # 일반 게시물 컴포넌트
|
|
│ │ │ └── notice/
|
|
│ │ │ └── ui/
|
|
│ │ │ └── notice-post.tsx # 공지사항 게시물 컴포넌트
|
|
│ │ └── widgets/
|
|
│ │ └── post/
|
|
│ │ ├── model/
|
|
│ │ │ ├── post-table-columns.tsx # 게시물 테이블 컬럼 정의
|
|
│ │ │ └── grid-view-table-columns.tsx # 그리드 뷰 테이블 컬럼 정의
|
|
│ │ └── ui/
|
|
│ │ ├── post-action.tsx # 게시물 액션 컴포넌트
|
|
│ │ ├── post-comment.tsx # 게시물 댓글 컴포넌트
|
|
│ │ ├── post-form.tsx # 게시물 등록/수정 폼
|
|
│ │ ├── post-page.tsx # 게시물 목록 페이지
|
|
│ │ ├── post.tsx # 게시물 상세 컴포넌트
|
|
│ │ └── posting-period-selector.tsx # 게시 기간 선택기
|
|
```
|
|
|
|
## 데이터 모델
|
|
|
|
### 게시물(Post) 인터페이스
|
|
|
|
```typescript
|
|
export interface Post {
|
|
rowNo: number; // 행 번호
|
|
bbsId: number; // 게시판 ID
|
|
pstNo: number; // 게시물 번호
|
|
pstTtl: string; // 게시물 제목
|
|
pstCn: string; // 게시물 내용
|
|
inqNocs: number; // 조회수
|
|
rfrncUrl: string; // 참조 URL
|
|
popupYn: string; // 팝업 여부
|
|
upndFixYn: string; // 상단 고정 여부
|
|
prdPstgYn: string; // 기간 게시 여부
|
|
rootPath: string; // 루트 경로
|
|
pstPath: string; // 게시물 경로
|
|
ansPstn: number; // 답변 위치
|
|
wrtrNm: string; // 작성자명
|
|
wrtrCplc: string; // 작성자 소속
|
|
atflCd: string; // 첨부파일 코드
|
|
regDt: string; // 등록일시
|
|
rgtrNm: string; // 등록자명
|
|
cmntCnt: number; // 댓글 수
|
|
}
|
|
```
|
|
|
|
### 게시물 상세 정보(PostInfo) 인터페이스
|
|
|
|
```typescript
|
|
export interface PostInfo extends Post {
|
|
pstCn: string; // 게시물 내용
|
|
rgtr: string; // 등록자
|
|
mdfcnDt: string; // 수정일시
|
|
mdfr: string; // 수정자
|
|
}
|
|
```
|
|
|
|
### 최근 게시물(RecentPost) 인터페이스
|
|
|
|
```typescript
|
|
export interface RecentPost extends Post {
|
|
bbsNm: string; // 게시판명
|
|
bbsTypeCd: string; // 게시판 유형 코드
|
|
}
|
|
```
|
|
|
|
### 게시물 이동(MovePost) 인터페이스
|
|
|
|
```typescript
|
|
export interface MovePost {
|
|
fromBbsId: number; // 출발 게시판 ID
|
|
toBbsId?: number; // 도착 게시판 ID
|
|
pstNo: number; // 게시물 번호
|
|
}
|
|
```
|
|
|
|
### 게시물 삭제(DeletePost) 인터페이스
|
|
|
|
```typescript
|
|
export interface DeletePost {
|
|
bbsId: number; // 게시판 ID
|
|
pstNo: number; // 게시물 번호
|
|
delRsn?: string; // 삭제 사유
|
|
}
|
|
```
|
|
|
|
### 게시물 검색 파라미터(PostParams) 인터페이스
|
|
|
|
```typescript
|
|
export interface PostParams extends PageableParams {
|
|
keywordType?: string; // 검색 키워드 유형 (제목, 내용, 작성자 등)
|
|
keyword?: string; // 검색 키워드
|
|
popupYn?: string; // 팝업 여부
|
|
upndFixYn?: string; // 상단 고정 여부
|
|
prdPstgYn?: string; // 기간 게시 여부
|
|
siteId?: string; // 사이트 ID
|
|
bbsTypeCd?: string; // 게시판 유형 코드
|
|
}
|
|
```
|
|
|
|
### 최근 게시물 검색 파라미터(RecentPostParams) 인터페이스
|
|
|
|
```typescript
|
|
export interface RecentPostParams extends PageableParams {
|
|
keywordType?: string; // 검색 키워드 유형
|
|
keyword?: string; // 검색 키워드
|
|
bbsId?: number | null; // 게시판 ID
|
|
delYn?: string; // 삭제 여부
|
|
frDateYmd?: string; // 시작 날짜
|
|
toDateYmd?: string; // 종료 날짜
|
|
}
|
|
```
|
|
|
|
### 게시물 폼 데이터(PostFormData) 인터페이스
|
|
|
|
Zod 스키마를 사용하여 폼 데이터의 유효성 검증을 수행합니다.
|
|
|
|
```typescript
|
|
export const postFormSchema = z.object({
|
|
bbsId: z.number(), // 게시판 ID
|
|
pstTtl: z.string().nonempty(), // 게시물 제목
|
|
pstCn: z.string().nullish(), // 게시물 내용
|
|
rfrncUrl: z.string().nullish(), // 참조 URL
|
|
popupYn: z.string().nullish(), // 팝업 여부
|
|
popupYnEtc: z.array(postEtcSchema).nullish(), // 팝업 관련 추가 정보
|
|
upndFixYn: z.string().nullish(), // 상단 고정 여부
|
|
upndFixYnEtc: z.array(postEtcSchema).nullish(), // 상단 고정 관련 추가 정보
|
|
prdPstgYn: z.string().nullish(), // 기간 게시 여부
|
|
prdPstgYnEtc: z.array(postEtcSchema).nullish(), // 기간 게시 관련 추가 정보
|
|
pstPswd: z.string(), // 게시물 비밀번호
|
|
wrtrNm: z.string().nullish(), // 작성자명
|
|
wrtrCplc: z.string().nullish(), // 작성자 소속
|
|
atflCd: z.string().nullish(), // 첨부파일 코드
|
|
parentPstNo: z.number().nullish(), // 부모 게시물 번호
|
|
});
|
|
```
|
|
|
|
## API 기능
|
|
|
|
게시물 관리 API는 다음과 같은 기능을 제공합니다:
|
|
|
|
### 1. 게시물 목록 조회
|
|
|
|
```typescript
|
|
getPostList: async (bbsId: number, params: PostParams): Promise<PostList> => {
|
|
const response = await client.get<PostList>(
|
|
`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}`,
|
|
{ params },
|
|
);
|
|
return response.data;
|
|
}
|
|
```
|
|
|
|
- **설명**: 특정 게시판의 게시물 목록을 페이지네이션과 함께 조회합니다.
|
|
- **파라미터**: `bbsId` (게시판 ID), `PostParams` (검색 조건)
|
|
- **반환값**: 페이지네이션된 게시물 목록 (`PostList`)
|
|
|
|
### 2. 최근 게시물 목록 조회
|
|
|
|
```typescript
|
|
getRecentPostList: async (params?: RecentPostParams): Promise<RecentPostList> => {
|
|
const response = await client.get<RecentPostList>(
|
|
`${ENDPOINT.BOARD_SERVICE.POSTS}/recentPosts`,
|
|
{ params },
|
|
);
|
|
return response.data;
|
|
}
|
|
```
|
|
|
|
- **설명**: 최근 게시물 목록을 조회합니다.
|
|
- **파라미터**: `RecentPostParams` (검색 조건)
|
|
- **반환값**: 페이지네이션된 최근 게시물 목록 (`RecentPostList`)
|
|
|
|
### 3. 게시물 상세 조회
|
|
|
|
```typescript
|
|
getPostInfo: async (bbsId: number, pstNo: number): Promise<PostInfo> => {
|
|
const response = await client.get<PostInfo>(
|
|
`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`,
|
|
);
|
|
return response.data;
|
|
}
|
|
```
|
|
|
|
- **설명**: 특정 게시물의 상세 정보를 조회합니다.
|
|
- **파라미터**: `bbsId` (게시판 ID), `pstNo` (게시물 번호)
|
|
- **반환값**: 게시물 상세 정보 (`PostInfo`)
|
|
|
|
### 4. 게시물 생성
|
|
|
|
```typescript
|
|
createPost: async (data: PostFormData): Promise<Post> => {
|
|
const validatedData = postFormSchema.parse(data);
|
|
const response = await client.post<Post>(
|
|
`${ENDPOINT.BOARD_SERVICE.POSTS}`,
|
|
validatedData,
|
|
);
|
|
return response.data;
|
|
}
|
|
```
|
|
|
|
- **설명**: 새로운 게시물을 생성합니다.
|
|
- **파라미터**: `PostFormData` (게시물 생성 데이터)
|
|
- **반환값**: 생성된 게시물 정보 (`Post`)
|
|
|
|
### 5. 게시물 수정
|
|
|
|
```typescript
|
|
updatePost: async (bbsId: number, pstNo: number, data: PostUpdateFormData): Promise<Post> => {
|
|
const validatedData = postUpdateFormSchema.parse(data);
|
|
const response = await client.put<Post>(
|
|
`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`,
|
|
validatedData,
|
|
);
|
|
return response.data;
|
|
}
|
|
```
|
|
|
|
- **설명**: 기존 게시물 정보를 수정합니다.
|
|
- **파라미터**: `bbsId` (게시판 ID), `pstNo` (게시물 번호), `PostUpdateFormData` (수정할 게시물 데이터)
|
|
- **반환값**: 수정된 게시물 정보 (`Post`)
|
|
|
|
### 6. 게시물 삭제
|
|
|
|
```typescript
|
|
deletePost: async (bbsId: number, pstNo: number, delRsn?: string): Promise<void> => {
|
|
await client.delete(`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`, {
|
|
params: { delRsn },
|
|
});
|
|
}
|
|
```
|
|
|
|
- **설명**: 게시물을 삭제합니다.
|
|
- **파라미터**: `bbsId` (게시판 ID), `pstNo` (게시물 번호), `delRsn` (삭제 사유, 선택적)
|
|
- **반환값**: void
|
|
|
|
### 7. 게시물 소프트 삭제 (여러 게시물)
|
|
|
|
```typescript
|
|
softDeletePost: async (data: DeletePost[]): Promise<void> => {
|
|
await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/softDeleteSels`, data);
|
|
}
|
|
```
|
|
|
|
- **설명**: 여러 게시물을 소프트 삭제합니다 (실제 삭제하지 않고 삭제 표시만 함).
|
|
- **파라미터**: `DeletePost[]` (삭제할 게시물 목록)
|
|
- **반환값**: void
|
|
|
|
### 8. 게시물 하드 삭제 (여러 게시물)
|
|
|
|
```typescript
|
|
hardDeletePost: async (data: DeletePost[]): Promise<void> => {
|
|
await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/hardDeleteSels`, data);
|
|
}
|
|
```
|
|
|
|
- **설명**: 여러 게시물을 하드 삭제합니다 (실제로 데이터베이스에서 삭제).
|
|
- **파라미터**: `DeletePost[]` (삭제할 게시물 목록)
|
|
- **반환값**: void
|
|
|
|
### 9. 게시물 이동
|
|
|
|
```typescript
|
|
movePost: async (data: MovePost[]): Promise<void> => {
|
|
await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/movePstByBbsId`, data);
|
|
}
|
|
```
|
|
|
|
- **설명**: 게시물을 다른 게시판으로 이동합니다.
|
|
- **파라미터**: `MovePost[]` (이동할 게시물 정보 목록)
|
|
- **반환값**: void
|
|
|
|
### 10. 게시물 복구
|
|
|
|
```typescript
|
|
restorePost: async (data: DeletePost[]): Promise<void> => {
|
|
await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/restoreSels`, data);
|
|
}
|
|
```
|
|
|
|
- **설명**: 소프트 삭제된 게시물을 복구합니다.
|
|
- **파라미터**: `DeletePost[]` (복구할 게시물 목록)
|
|
- **반환값**: void
|
|
|
|
## 프로그램 흐름
|
|
|
|
### 1. 게시물 목록 조회 흐름
|
|
|
|
1. 사용자가 게시판 페이지에 접근
|
|
2. `useMenuStore`를 통해 현재 게시판 정보 로드
|
|
3. React Query를 사용하여 `getPostList` API 호출
|
|
4. 상단 고정 게시물이 있는 경우 별도로 조회하여 목록 상단에 표시
|
|
5. 검색 조건 변경 시 쿼리 파라미터 업데이트 및 API 재호출
|
|
6. 응답 데이터를 TanStack Table을 사용하여 테이블 형태로 표시
|
|
7. 게시판 유형에 따라 일반 테이블 또는 그리드 뷰로 표시
|
|
|
|
### 2. 게시물 상세 조회 흐름
|
|
|
|
1. 사용자가 게시물 목록에서 특정 게시물 클릭
|
|
2. 해당 게시물의 상세 페이지로 이동 (`/bbs/{bbsId}/{pstNo}`)
|
|
3. React Query를 사용하여 `getPostInfo` API 호출
|
|
4. 게시물 상세 정보 및 첨부파일 정보 로드
|
|
5. 게시판 유형에 따라 적절한 상세 보기 컴포넌트 렌더링
|
|
- 일반 게시물: `normal-post.tsx`
|
|
- 이미지 게시물: `image-post.tsx`
|
|
- 동영상 게시물: `movie-post.tsx`
|
|
- 공지사항: `notice-post.tsx`
|
|
|
|
### 3. 게시물 등록 흐름
|
|
|
|
1. 사용자가 게시물 등록 버튼 클릭
|
|
2. 게시물 등록 페이지로 이동 (`/bbs/{bbsId}/register`)
|
|
3. React Hook Form과 Zod를 사용하여 폼 데이터 관리 및 유효성 검증
|
|
4. 첨부파일 업로드 시 `AttachmentApi`를 통해 파일 업로드 및 `atflCd` 획득
|
|
5. 저장 버튼 클릭 시 확인 다이얼로그 표시 후 `createPost` API 호출
|
|
6. 성공 시 게시물 목록 페이지로 리다이렉트
|
|
|
|
### 4. 게시물 수정 흐름
|
|
|
|
1. 사용자가 게시물 상세 페이지에서 수정 버튼 클릭
|
|
2. 게시물 수정 페이지로 이동 (`/bbs/{bbsId}/{pstNo}/modify`)
|
|
3. `getPostInfo` API를 호출하여 기존 게시물 데이터 로드
|
|
4. 기존 첨부파일 정보 로드 및 표시
|
|
5. 사용자가 데이터 수정 후 저장 버튼 클릭
|
|
6. 확인 다이얼로그 표시 후 `updatePost` API 호출
|
|
7. 성공 시 게시물 상세 페이지로 리다이렉트
|
|
|
|
### 5. 게시물 삭제 흐름
|
|
|
|
1. 사용자가 게시물 상세 페이지에서 삭제 버튼 클릭 또는 목록에서 여러 게시물 선택 후 삭제 버튼 클릭
|
|
2. 삭제 사유 입력 다이얼로그 표시
|
|
3. 사용자가 삭제 사유 입력 후 확인
|
|
4. 단일 게시물 삭제 시 `deletePost` API 호출, 여러 게시물 삭제 시 `softDeletePost` 또는 `hardDeletePost` API 호출
|
|
5. 성공 시 게시물 목록 페이지로 리다이렉트 또는 목록 새로고침
|
|
|
|
## 주요 컴포넌트
|
|
|
|
### 1. PostPage 컴포넌트
|
|
|
|
게시물 목록을 조회하고 표시하는 페이지 컴포넌트입니다.
|
|
|
|
- **기능**:
|
|
- 게시물 검색 (제목, 내용, 작성자 등)
|
|
- 페이지네이션
|
|
- 페이지 크기 조정
|
|
- 게시물 목록 표시 (테이블 또는 그리드 뷰)
|
|
- 게시물 등록 페이지로 이동
|
|
- 게시물 상세 페이지로 이동 (행 클릭)
|
|
- 선택한 게시물 삭제
|
|
|
|
### 2. PostForm 컴포넌트
|
|
|
|
게시물 등록 및 수정에 사용되는 폼 컴포넌트입니다.
|
|
|
|
- **기능**:
|
|
- 게시물 정보 입력/수정 (제목, 내용, 작성자 등)
|
|
- 첨부파일 업로드 및 관리
|
|
- 참조 URL 입력 (게시판 설정에 따라)
|
|
- 팝업 게시 설정 (게시판 설정에 따라)
|
|
- 상단 고정 설정 (게시판 설정에 따라)
|
|
- 기간 게시 설정 (게시판 설정에 따라)
|
|
- 저장 확인 다이얼로그
|
|
- 취소 기능
|
|
|
|
### 3. Post 컴포넌트
|
|
|
|
게시물 상세 정보를 표시하는 컴포넌트입니다.
|
|
|
|
- **기능**:
|
|
- 게시물 상세 정보 표시
|
|
- 첨부파일 다운로드
|
|
- 수정/삭제 버튼
|
|
- 목록으로 돌아가기
|
|
- 댓글 표시 및 관리 (게시판 설정에 따라)
|
|
|
|
### 4. PostComment 컴포넌트
|
|
|
|
게시물 댓글을 표시하고 관리하는 컴포넌트입니다.
|
|
|
|
- **기능**:
|
|
- 댓글 목록 표시
|
|
- 댓글 등록
|
|
- 댓글 수정/삭제
|
|
- 댓글 페이지네이션
|
|
|
|
### 5. PostingPeriodSelector 컴포넌트
|
|
|
|
게시 기간을 선택하는 컴포넌트입니다.
|
|
|
|
- **기능**:
|
|
- 게시 기간 유형 선택
|
|
- 시작일/종료일 선택
|
|
- 게시 기간 설정
|
|
|
|
### 6. 게시물 유형별 컴포넌트
|
|
|
|
게시판 유형에 따라 다양한 게시물 컴포넌트를 제공합니다.
|
|
|
|
- **NormalPost**: 일반 텍스트 게시물 컴포넌트
|
|
- **ImagePost**: 이미지 게시물 컴포넌트 (이미지 갤러리 형태)
|
|
- **MoviePost**: 동영상 게시물 컴포넌트 (동영상 플레이어 포함)
|
|
- **NoticePost**: 공지사항 게시물 컴포넌트
|
|
|
|
## 아키텍처 특징
|
|
|
|
1. **계층 분리**: API, 모델, UI 컴포넌트가 명확히 분리되어 있습니다.
|
|
2. **타입 안전성**: TypeScript 인터페이스와 Zod 스키마를 통한 타입 검증을 제공합니다.
|
|
3. **컴포넌트 재사용**: 공통 컴포넌트를 활용하여 코드 중복을 최소화합니다.
|
|
4. **유효성 검증**: Zod 스키마를 사용하여 폼 데이터의 유효성을 검증합니다.
|
|
5. **상태 관리**: React Query를 통한 서버 상태 관리와 Zustand를 통한 클라이언트 상태 관리를 제공합니다.
|
|
6. **조건부 렌더링**: 게시판 설정에 따라 UI 요소를 조건부로 렌더링합니다.
|
|
7. **다양한 게시물 유형 지원**: 일반, 이미지, 동영상, 공지사항 등 다양한 게시물 유형을 지원합니다.
|
|
|
|
## 확장 가능성
|
|
|
|
1. **다국어 지원**: 게시물 내용의 다국어 지원 기능 추가
|
|
2. **게시물 버전 관리**: 게시물 수정 이력 관리 기능 추가
|
|
3. **게시물 예약 발행**: 특정 시간에 자동으로 게시되는 기능 추가
|
|
4. **게시물 통계**: 조회수, 좋아요 등 게시물 통계 기능 강화
|
|
5. **게시물 공유**: 소셜 미디어 공유 기능 추가
|
|
6. **게시물 알림**: 새 게시물 알림 기능 추가
|
|
7. **게시물 태그**: 게시물 태그 및 카테고리 기능 추가
|
|
|
|
## 주의사항
|
|
|
|
1. 게시물 삭제 시 연관된 첨부파일, 댓글 등의 처리에 주의가 필요합니다.
|
|
2. 게시물 이동 시 게시판 유형 간 호환성 문제가 발생할 수 있습니다.
|
|
3. 첨부파일 업로드 시 파일 크기 및 유형 제한을 준수해야 합니다.
|
|
4. 게시 기간 설정 시 시간대(timezone) 처리에 주의가 필요합니다.
|
|
5. 비로그인 사용자의 게시물 작성 시 비밀번호 관리에 주의가 필요합니다.
|