feat: Add bulletin board system

- Add BoardCategory and BoardPost models with multi-language support
- Add bulletin API endpoints (CRUD, notice toggle, pin toggle)
- Add board_enabled setting to control menu visibility
- Create frontend board pages (list, detail, write, edit)
- Create admin board management and category management pages
- Update Header.tsx with conditional Board menu between Inquiry and Contact Us
- Update admin settings with board_enabled toggle
- Add Board menu to admin sidebar

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
AutonetSellCar Deploy
2026-01-10 01:34:41 +09:00
parent 04bec0d2c7
commit e0c1f4540b
17 changed files with 2630 additions and 2 deletions

View File

@@ -0,0 +1,125 @@
"""
Bulletin Board Schemas - 게시판 스키마
"""
from datetime import datetime
from typing import Optional, List
from pydantic import BaseModel
# ============ Category Schemas ============
class BoardCategoryBase(BaseModel):
name: str
name_en: Optional[str] = None
name_mn: Optional[str] = None
name_ru: Optional[str] = None
slug: str
description: Optional[str] = None
sort_order: int = 0
is_active: bool = True
class BoardCategoryCreate(BoardCategoryBase):
pass
class BoardCategoryUpdate(BaseModel):
name: Optional[str] = None
name_en: Optional[str] = None
name_mn: Optional[str] = None
name_ru: Optional[str] = None
slug: Optional[str] = None
description: Optional[str] = None
sort_order: Optional[int] = None
is_active: Optional[bool] = None
class BoardCategoryResponse(BoardCategoryBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = None
post_count: int = 0
class Config:
from_attributes = True
# ============ Post Schemas ============
class BoardPostBase(BaseModel):
title: str
content: str
category_id: int
class BoardPostCreate(BoardPostBase):
is_notice: bool = False # 관리자만 true 가능
class BoardPostUpdate(BaseModel):
title: Optional[str] = None
content: Optional[str] = None
category_id: Optional[int] = None
is_notice: Optional[bool] = None
is_pinned: Optional[bool] = None
is_published: Optional[bool] = None
class AuthorResponse(BaseModel):
id: int
name: Optional[str] = None
email: str
is_admin: bool = False
class Config:
from_attributes = True
class BoardPostResponse(BaseModel):
id: int
title: str
content: str
category_id: int
category: Optional[BoardCategoryResponse] = None
author_id: int
author: Optional[AuthorResponse] = None
is_notice: bool
is_pinned: bool
is_published: bool
view_count: int
created_at: datetime
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
class BoardPostListItem(BaseModel):
"""목록에서 보여줄 간략한 정보"""
id: int
title: str
category_id: int
category_name: Optional[str] = None
author_id: int
author_name: Optional[str] = None
is_notice: bool
is_pinned: bool
view_count: int
created_at: datetime
class Config:
from_attributes = True
class BoardPostListResponse(BaseModel):
posts: List[BoardPostListItem]
notices: List[BoardPostListItem] # 공지사항 (상단 고정)
total: int
page: int
page_size: int
total_pages: int
class BoardCategoryListResponse(BaseModel):
categories: List[BoardCategoryResponse]
total: int