Files
distribution_erp/.claude/rules/pages.md
T
chpark 6af863199f feat: 모모유통 유통관리 ERP (Next.js 16) — MOMO 브랜딩 + distribution DB + momo.junggomoa.com
- fito-nextjs 기반으로 재구성
- 로그인: MOMO 로고 + 모모유통 + 유통관리 ERP, 하단에 본사/지사 주소 표시
- 사이드바 상단: MOMO 아이콘 + 모모유통 + 유통관리 ERP
- 파비콘: /src/app/icon.svg (MOMO 그린 배지)
- layout.tsx title: 모모유통 | 유통관리 ERP
- DB: 183.99.177.40:5432/distribution (fito 스키마 import 완료)
- Traefik: Host(momo.junggomoa.com), 컨테이너 momo-erp
2026-04-25 02:44:40 +09:00

1.8 KiB

globs
globs
src/app/(main)/**/*.tsx, src/app/(auth)/**/*.tsx, src/app/admin-panel/**/*.tsx

페이지 코딩 규칙

기본 구조

모든 페이지는 "use client" 클라이언트 컴포넌트:

"use client";

import { useState, useCallback } from "react";
import { DataGrid, GridColumn } from "@/components/grid/data-grid";
import { SearchForm, SearchField } from "@/components/layout/search-form";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { CodeSelect } from "@/components/ui/code-select";
import Swal from "sweetalert2";

페이지 레이아웃 순서

  1. 제목: <h2 className="text-lg font-bold text-gray-800 mb-4">{제목}</h2>
  2. 검색 폼: <SearchForm> + <SearchField>
  3. 버튼 영역: 조회/등록/삭제
  4. 데이터 그리드: <DataGrid> + <Pagination>

데이터 조회

const [data, setData] = useState<Record<string, unknown>[]>([]);

const fetchData = useCallback(async () => {
  const res = await fetch("/api/{domain}/{resource}", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ year, category_cd }),
  });
  if (res.ok) {
    const json = await res.json();
    setData(json.RESULTLIST || []);
  }
}, [year, category_cd]);

팝업

const left = (window.screen.width - 1200) / 2;
const top = (window.screen.height - 550) / 2;
window.open(url, "formPopup", `width=1200,height=550,left=${left},top=${top}`);

삭제 확인

if (selectedRows.length === 0) {
  Swal.fire("알림", "삭제할 항목을 선택하세요.", "warning");
  return;
}

DataGrid 높이

페이지별 calc(100vh - 350px) ~ calc(100vh - 400px) 사용.

년도 필터 (자주 사용)

Array.from({ length: 5 }, (_, i) => new Date().getFullYear() - i)