๊ฐ์์ง ์ค์ข /๋ฐ๊ฒฌ ๊ฒ์๋ฌผ ๊ด๋ฆฌ ์์คํ ์ ๊ด๋ฆฌ์ ๋์๋ณด๋์ ๋๋ค. Next.js 15์ React 19๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋์์ต๋๋ค.
- ํ๋ก์ ํธ ๊ฐ์
- ์ฃผ์ ๊ธฐ๋ฅ
- ๊ธฐ์ ์คํ
- ํ๋ก์ ํธ ๊ตฌ์กฐ
- ์์ํ๊ธฐ
- ํ๊ฒฝ ์ค์
- ์ฃผ์ ํ์ด์ง
- API ๊ตฌ์กฐ
- ์ฃผ์ ์ปดํฌ๋ํธ
๊ฐ์์งํด์ด ๊ด๋ฆฌ์ ๋์๋ณด๋๋ ์ค์ข /๋ฐ๊ฒฌ ๊ฒ์๋ฌผ ํ๋ซํผ์ ๊ด๋ฆฌ์์ฉ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. ๊ด๋ฆฌ์๋ ์ด ๋์๋ณด๋๋ฅผ ํตํด ์ฌ์ฉ์, ๊ฒ์๋ฌผ, ์ ๊ณ ๋ด์ญ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
- ๐ JWT ๊ธฐ๋ฐ ์ธ์ฆ ์์คํ
- ๐ ์ค์๊ฐ ๋ฐ์ดํฐ ์กฐํ ๋ฐ ๊ด๋ฆฌ
- ๐จ ๋ฐ์ํ ๋์์ธ (๋ชจ๋ฐ์ผ/๋ฐ์คํฌํฑ ์ง์)
- ๐ ๊ฒ์ ๋ฐ ํํฐ๋ง ๊ธฐ๋ฅ
- ๐ ํ์ด์ง๋ค์ด์ ์ง์
- ๐๏ธ ๊ฒ์๋ฌผ ๋ฐ ์ฌ์ฉ์ ์ญ์ ๊ธฐ๋ฅ
โ ๏ธ ์ ๊ณ ๋ด์ญ ๊ด๋ฆฌ ๋ฐ ์ฒ๋ฆฌ
- ์ฌ์ฉ์ ๋ชฉ๋ก ์กฐํ: ์ ์ฒด ์ฌ์ฉ์ ๋ชฉ๋ก์ ํ์ด์ง๋ค์ด์ ๊ณผ ํจ๊ป ์กฐํ
- ๊ฒ์ ๊ธฐ๋ฅ: ์ฌ์ฉ์๋ช ๋๋ ์ด๋ฉ์ผ๋ก ๊ฒ์
- ์ํ ๊ด๋ฆฌ: ๊ณ์ ํ์ฑํ/๋นํ์ฑํ ์ฒ๋ฆฌ
- ๊ณ์ ์ญ์ : ์ฌ์ฉ์ ๊ณ์ ์ญ์ ๊ธฐ๋ฅ
- ์์ธ ์ ๋ณด: ์ฌ์ฉ์ ํ๋ ์์ธ ์ ๋ณด ๋ชจ๋ฌ
- ๊ฒ์๋ฌผ ๋ชฉ๋ก ์กฐํ: ์ ์ฒด/๋ฐ๊ฒฌํ์ด์/์์ด๋ฒ๋ ธ์ด์ ๊ฒ์๋ฌผ ํํฐ๋ง
- AI ์ด๋ฏธ์ง ํํฐ: AI ์์ฑ ์ด๋ฏธ์ง ๊ฒ์๋ฌผ๋ง ์กฐํ
- ๊ฒ์๋ฌผ ์ญ์ : ๋ถ์ ์ ํ ๊ฒ์๋ฌผ ์ญ์ ๊ธฐ๋ฅ
- ์์ธ ์ ๋ณด: ๊ฒ์๋ฌผ ์์ธ ์ ๋ณด ๋ชจ๋ฌ (๊ฐ์์ง ์ ๋ณด, ์์น ์ ๋ณด ํฌํจ)
- ์ง๋ ์ฐ๋: Google Maps๋ฅผ ํตํ ์์น ์ ๋ณด ํ์
- ์ ๊ณ ๋ชฉ๋ก ์กฐํ: ์ ์ฒด ์ ๊ณ ๋ด์ญ ์กฐํ
- ์ ๊ณ ์์ธ๋ณด๊ธฐ: ์ ๊ณ ์ฌ์ ๋ฐ ์์ธ ์ ๋ณด ํ์ธ
- ๊ฒ์๋ฌผ ์ฐ๋: ์ ๊ณ ๋ ๊ฒ์๋ฌผ ๋ฐ๋ก ํ์ธ
- ์ฒ๋ฆฌ ๊ธฐ๋ฅ:
- ์ ๊ณ ๋ฌด์ ์ฒ๋ฆฌ
- ์ ๊ณ ๋ ๊ฒ์๋ฌผ ์ญ์
- ๋ก๊ทธ์ธ: ์ด๋ฉ์ผ/๋น๋ฐ๋ฒํธ ๊ธฐ๋ฐ ๋ก๊ทธ์ธ
- ํ ํฐ ๊ด๋ฆฌ: JWT ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ
- ์๋ ๋ฆฌ๋ค์ด๋ ํธ: ๋ฏธ์ธ์ฆ ์ ๋ก๊ทธ์ธ ํ์ด์ง๋ก ์๋ ์ด๋
- ์ธ์ ๊ด๋ฆฌ: ๋ก์ปฌ ์คํ ๋ฆฌ์ง๋ฅผ ํตํ ์ธ์ ์ ์ง
- Framework: Next.js 15.5.6 (App Router)
- UI Library: React 19.1.0
- Language: TypeScript 5
- Styling: Tailwind CSS 3.4.0
- HTTP Client: Axios 1.12.2
- UI Components:
- @headlessui/react 2.2.9
- @heroicons/react 2.2.0
- Maps: @react-google-maps/api 2.20.7
- Linting: ESLint 9
- Build Tool: Turbopack (Next.js ๋ด์ฅ)
- Package Manager: npm/yarn
fe-admin/
โโโ src/
โ โโโ app/ # Next.js App Router ํ์ด์ง
โ โ โโโ admin/ # ๊ด๋ฆฌ์ ํ์ด์ง
โ โ โ โโโ members/ # ์ฌ์ฉ์ ๊ด๋ฆฌ
โ โ โ โโโ posts/ # ๊ฒ์๋ฌผ ๊ด๋ฆฌ
โ โ โ โโโ reports/ # ์ ๊ณ ๋ด์ญ ๊ด๋ฆฌ
โ โ โ โโโ layout.tsx # ๊ด๋ฆฌ์ ๋ ์ด์์
โ โ โ โโโ page.tsx # ๊ด๋ฆฌ์ ๋ฉ์ธ (๋ฆฌ๋ค์ด๋ ํธ)
โ โ โโโ api/ # API ๋ผ์ฐํธ (ํ๋ก์)
โ โ โ โโโ admin/ # ๊ด๋ฆฌ์ API
โ โ โ โโโ auth/ # ์ธ์ฆ API
โ โ โโโ login/ # ๋ก๊ทธ์ธ ํ์ด์ง
โ โ โโโ layout.tsx # ๋ฃจํธ ๋ ์ด์์
โ โ โโโ page.tsx # ํ ํ์ด์ง
โ โโโ components/ # ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ
โ โ โโโ badge/ # ์ํ ๋ฐฐ์ง ์ปดํฌ๋ํธ
โ โ โโโ filters/ # ํํฐ ์ปดํฌ๋ํธ
โ โ โโโ layout/ # ๋ ์ด์์ ์ปดํฌ๋ํธ
โ โ โโโ tables/ # ํ
์ด๋ธ ์ปดํฌ๋ํธ
โ โ โโโ tabs/ # ํญ ์ปดํฌ๋ํธ
โ โ โโโ ui/ # UI ์ปดํฌ๋ํธ
โ โ โโโ AiToggle.tsx # AI ํํฐ ํ ๊ธ
โ โ โโโ FilterButtons.tsx # ๊ฒ์๋ฌผ ํ์
ํํฐ
โ โ โโโ MembersDetailModal.tsx
โ โ โโโ PostDetailModal.tsx
โ โ โโโ PostsTable.tsx
โ โ โโโ ReportDetailModal.tsx
โ โ โโโ Sidebar.tsx
โ โโโ lib/ # ์ ํธ๋ฆฌํฐ ๋ฐ ์ค์
โ โโโ api-client.ts # API ํด๋ผ์ด์ธํธ
โ โโโ url-utils.ts # URL ์ ํธ๋ฆฌํฐ
โ โโโ mock/ # ๋ชฉ์
๋ฐ์ดํฐ
โโโ public/ # ์ ์ ํ์ผ
โโโ next.config.js # Next.js ์ค์
โโโ tailwind.config.js # Tailwind CSS ์ค์
โโโ package.json # ํ๋ก์ ํธ ์์กด์ฑ
- Node.js 18 ์ด์
- npm ๋๋ yarn
# ์์กด์ฑ ์ค์น
npm install
# ๋๋
yarn install# ๊ฐ๋ฐ ์๋ฒ ์์ (Turbopack ์ฌ์ฉ)
npm run dev
# ๋๋
yarn dev๋ธ๋ผ์ฐ์ ์์ http://localhost:3000์ ์ด์ด ํ์ธํ์ธ์.
# ํ๋ก๋์
๋น๋
npm run build
# ๋๋
yarn build
# ํ๋ก๋์
์๋ฒ ์์
npm start
# ๋๋
yarn startํ๋ก์ ํธ๋ ์ธ๋ถ ๋ฐฑ์๋ ์๋ฒ(http://54.180.54.51:8080)์ ํต์ ํฉ๋๋ค.
next.config.js์์ API ํ๋ก์ ์ค์ ์ ํ์ธํ ์ ์์ต๋๋ค:
async rewrites() {
return [
{
source: "/api/:path*",
destination: "http://54.180.54.51:8080/api/:path*",
},
];
}๊ฐ๋ฐ ํ๊ฒฝ์์ ๋ชฉ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํ์ธ์:
# .env.local
NEXT_PUBLIC_USE_MOCK=trueS3 ์ด๋ฏธ์ง๋ฅผ ํ์ํ๊ธฐ ์ํด next.config.js์ ์ด๋ฏธ์ง ๋๋ฉ์ธ์ด ์ค์ ๋์ด ์์ต๋๋ค:
images: {
remotePatterns: [
{
protocol: "https",
hostname: "gangajikimi-server.s3.ap-northeast-2.amazonaws.com",
pathname: "/**",
},
],
}- ์ด๋ฉ์ผ/๋น๋ฐ๋ฒํธ ์ ๋ ฅ
- JWT ํ ํฐ ๋ฐ๊ธ ๋ฐ ์ ์ฅ
- ๋ก๊ทธ์ธ ์ฑ๊ณต ์
/admin/members๋ก ๋ฆฌ๋ค์ด๋ ํธ
- ์ฌ์ฉ์ ๋ชฉ๋ก ํ ์ด๋ธ
- ๊ฒ์ ๊ธฐ๋ฅ (์ฌ์ฉ์๋ช /์ด๋ฉ์ผ)
- ํ์ด์ง๋ค์ด์ (๊ธฐ๋ณธ 20๊ฐ/ํ์ด์ง)
- ๊ณ์ ์ํ ๋ณ๊ฒฝ (ํ์ฑํ/๋นํ์ฑํ)
- ๊ณ์ ์ญ์
- ์ฌ์ฉ์ ์์ธ ์ ๋ณด ๋ชจ๋ฌ
- ๊ฒ์๋ฌผ ๋ชฉ๋ก ํ ์ด๋ธ
- ํํฐ: ์ ์ฒด/๋ฐ๊ฒฌํ์ด์/์์ด๋ฒ๋ ธ์ด์
- AI ์ด๋ฏธ์ง ํํฐ ํ ๊ธ
- ๊ฒ์๋ฌผ ์ญ์
- ๊ฒ์๋ฌผ ์์ธ ์ ๋ณด ๋ชจ๋ฌ:
- ๊ฒ์๋ฌผ ์ ๋ณด ํญ
- ๊ฐ์์ง ์ ๋ณด ํญ
- ์์น ์ ๋ณด ํญ (Google Maps)
- ์ ๊ณ ๋ชฉ๋ก ํ ์ด๋ธ
- ์ ๊ณ ์ฌ์ , ์ ๊ณ ์, ์ ๊ณ ์ผ ํ์
- ์ ๊ณ ์ํ ๋ฐฐ์ง
- ์ ๊ณ ์์ธ๋ณด๊ธฐ ๋ชจ๋ฌ
- ์ ๊ณ ๋ ๊ฒ์๋ฌผ ๋ฐ๋ก๊ฐ๊ธฐ
- ๊ด๋ฆฌ์ ์์
:
- ์ ๊ณ ๋ฌด์ ์ฒ๋ฆฌ
- ์ ๊ณ ๋ ๊ฒ์๋ฌผ ์ญ์
POST /api/auth/login- ๋ก๊ทธ์ธ
GET /api/admin/members- ์ฌ์ฉ์ ๋ชฉ๋ก ์กฐํGET /api/admin/members/[id]- ์ฌ์ฉ์ ์์ธ ์กฐํPATCH /api/admin/members/[id]/status- ์ฌ์ฉ์ ์ํ ๋ณ๊ฒฝDELETE /api/admin/members/[id]- ์ฌ์ฉ์ ์ญ์
GET /api/admin/posts- ๊ฒ์๋ฌผ ๋ชฉ๋ก ์กฐํGET /api/admin/posts/[type]/[id]- ๊ฒ์๋ฌผ ์์ธ ์กฐํDELETE /api/admin/posts/[type]/[id]/delete- ๊ฒ์๋ฌผ ์ญ์
GET /api/admin/reports- ์ ๊ณ ๋ชฉ๋ก ์กฐํGET /api/admin/reports/[type]/[reportId]- ์ ๊ณ ์์ธ ์กฐํPATCH /api/admin/reports/[type]/[reportId]/ignore- ์ ๊ณ ๋ฌด์ ์ฒ๋ฆฌDELETE /api/admin/reports/[type]/[reportId]/delete- ์ ๊ณ ๋ ๊ฒ์๋ฌผ ์ญ์
src/lib/api-client.ts์์ API ํด๋ผ์ด์ธํธ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค:
apiClient: ์ค์ ์๋ฒ์ ํต์ (๊ฒ์๋ฌผ, ์ ๊ณ ๊ด๋ฆฌ)mockApiClient: ๋ชฉ์ ๋ฐ์ดํฐ ์ฌ์ฉ (์ฌ์ฉ์ ๊ด๋ฆฌ)
- Sidebar: ์ฌ์ด๋๋ฐ ๋ค๋น๊ฒ์ด์ ๋ฉ๋ด
- AdminHeader: ์๋จ ํค๋ (์ฌ์ด๋๋ฐ ํ ๊ธ, ์ฌ์ฉ์ ์ ๋ณด, ๋ก๊ทธ์์)
- AdminTable: ๋ฒ์ฉ ๊ด๋ฆฌ์ ํ ์ด๋ธ
- PostsTable: ๊ฒ์๋ฌผ ์ ์ฉ ํ ์ด๋ธ
- TablePagination: ํ์ด์ง๋ค์ด์ ์ปดํฌ๋ํธ
- MembersDetailModal: ์ฌ์ฉ์ ์์ธ ์ ๋ณด ๋ชจ๋ฌ
- PostDetailModal: ๊ฒ์๋ฌผ ์์ธ ์ ๋ณด ๋ชจ๋ฌ (ํญ ๊ตฌ์กฐ)
- ReportDetailModal: ์ ๊ณ ์์ธ ์ ๋ณด ๋ชจ๋ฌ
- FilterButtons: ๊ฒ์๋ฌผ ํ์ ํํฐ (์ ์ฒด/๋ฐ๊ฒฌ/์ค์ข )
- SearchFilter: ๊ฒ์ ์ ๋ ฅ ํํฐ
- AiToggle: AI ์ด๋ฏธ์ง ํํฐ ํ ๊ธ
- ActivityBadge: ์ฌ์ฉ์ ํ๋ ์ํ ๋ฐฐ์ง
- StatusBadge: ์ผ๋ฐ ์ํ ๋ฐฐ์ง
- ReportStatusBadge: ์ ๊ณ ์ํ ๋ฐฐ์ง
- JWT ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ
- ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ํ ํฐ ์ ์ฅ
- API ์์ฒญ ์ Authorization ํค๋์ ํ ํฐ ํฌํจ
- ํ ํฐ ๋ง๋ฃ ์ ์๋ ๋ก๊ทธ์์ ๋ฐ ๋ก๊ทธ์ธ ํ์ด์ง ๋ฆฌ๋ค์ด๋ ํธ
- ๊ด๋ฆฌ์ ํ์ด์ง ์ ๊ทผ ์ ์ธ์ฆ ํ์ธ
- Tailwind CSS๋ฅผ ์ฌ์ฉํ ์ ํธ๋ฆฌํฐ ๊ธฐ๋ฐ ์คํ์ผ๋ง
- ๋ฐ์ํ ๋์์ธ (๋ชจ๋ฐ์ผ/ํ๋ธ๋ฆฟ/๋ฐ์คํฌํฑ)
- ๋คํฌ ๋ชจ๋๋ ๋ฏธ์ง์ (ํฅํ ์ถ๊ฐ ๊ฐ๋ฅ)
๊ฐ๋ฐ ์ค ๋ฐฑ์๋ ์๋ฒ๊ฐ ์์ ๋ ๋ชฉ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
.env.localํ์ผ ์์ฑNEXT_PUBLIC_USE_MOCK=true์ค์ - ๊ฐ๋ฐ ์๋ฒ ์ฌ์์
- ๋ธ๋ผ์ฐ์ ์ฝ์์์ API ์์ฒญ/์๋ต ๋ก๊ทธ ํ์ธ
- ๋คํธ์ํฌ ํญ์์ ์ค์ HTTP ์์ฒญ ํ์ธ
- Next.js ์๋ฒ ์ฝ์์์ ์๋ฒ ์ฌ์ด๋ ๋ก๊ทธ ํ์ธ
์ด ํ๋ก์ ํธ๋ ๋น๊ณต๊ฐ ํ๋ก์ ํธ์ ๋๋ค.
ํ๋ก์ ํธ ๊ด๋ จ ๋ฌธ์์ฌํญ์ด ์์ผ์๋ฉด ๊ฐ๋ฐํ์ ์ฐ๋ฝํด์ฃผ์ธ์.