- _index.md: 문서 목록 및 버전 관리 - 01~09: 아키텍처, API패턴, 컴포넌트, 폼, 스타일, 인증, 대시보드, 컨벤션 - 10: 문서 API 연동 스펙 (api-specs에서 이관) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
267 lines
7.0 KiB
Markdown
267 lines
7.0 KiB
Markdown
# 09. 코딩 컨벤션
|
|
|
|
> **대상**: 프론트엔드 개발자
|
|
> **버전**: 1.0.0
|
|
> **최종 수정**: 2026-03-09
|
|
|
|
---
|
|
|
|
## 1. 네이밍 규칙
|
|
|
|
### 파일/폴더
|
|
|
|
| 대상 | 규칙 | 예시 |
|
|
|------|------|------|
|
|
| 컴포넌트 파일 | PascalCase | `BillManagement.tsx` |
|
|
| 컴포넌트 폴더 | PascalCase | `BillManagement/` |
|
|
| 유틸리티 | camelCase | `query-params.ts`, `amount.ts` |
|
|
| 타입 파일 | camelCase | `types.ts` |
|
|
| Server Action | camelCase | `actions.ts` |
|
|
| 훅 | camelCase (use 접두사) | `useCEODashboard.ts` |
|
|
| 페이지 라우트 | kebab-case | `general-journal-entry/page.tsx` |
|
|
|
|
### 변수/함수
|
|
|
|
| 대상 | 규칙 | 예시 |
|
|
|------|------|------|
|
|
| 컴포넌트 | PascalCase | `function BillManagement()` |
|
|
| 함수 | camelCase | `handleSave`, `loadData` |
|
|
| 이벤트 핸들러 | handle 접두사 | `handleClick`, `handleSubmit` |
|
|
| 콜백 prop | on 접두사 | `onSave`, `onChange` |
|
|
| boolean | is/has/show 접두사 | `isLoading`, `hasError`, `showModal` |
|
|
| 상수 | UPPER_SNAKE_CASE | `PERIOD_BUTTONS`, `TYPE_WELFARE` |
|
|
| 타입/인터페이스 | PascalCase | `BillRecord`, `SearchParams` |
|
|
|
|
---
|
|
|
|
## 2. 파일 배치 규칙
|
|
|
|
### 도메인 컴포넌트 구조
|
|
|
|
```
|
|
src/components/accounting/BillManagement/
|
|
├── index.tsx # 메인 컴포넌트 (export)
|
|
├── actions.ts # Server Actions ('use server')
|
|
├── types.ts # 타입 정의
|
|
├── BillDetail.tsx # 하위 컴포넌트
|
|
├── BillForm.tsx # 폼 컴포넌트
|
|
└── schema.ts # Zod 스키마 (선택)
|
|
```
|
|
|
|
### 배치 원칙
|
|
|
|
| 파일 | 위치 |
|
|
|------|------|
|
|
| 비즈니스 로직 컴포넌트 | `src/components/{domain}/{ComponentName}/` |
|
|
| 공통 UI 컴포넌트 | `src/components/ui/` (shadcn/ui) |
|
|
| 공통 조합 컴포넌트 | `src/components/organisms/` |
|
|
| 도메인 공통 | `src/components/{domain}/common/` |
|
|
| 전체 공통 | `src/components/common/` |
|
|
| API 유틸 | `src/lib/api/` |
|
|
| 범용 유틸 | `src/lib/utils/` |
|
|
| 훅 | `src/hooks/` |
|
|
| 전역 타입 | `src/types/` |
|
|
|
|
---
|
|
|
|
## 3. Import 규칙
|
|
|
|
### 순서
|
|
|
|
```typescript
|
|
// 1. React/Next.js
|
|
import { useState, useCallback } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
// 2. 외부 라이브러리
|
|
import { toast } from 'sonner';
|
|
import { z } from 'zod';
|
|
|
|
// 3. UI 컴포넌트 (@/components/ui)
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card } from '@/components/ui/card';
|
|
|
|
// 4. 공통 컴포넌트 (@/components/organisms, molecules, atoms)
|
|
import { PageLayout } from '@/components/organisms/PageLayout';
|
|
import { FormField } from '@/components/molecules/FormField';
|
|
|
|
// 5. 도메인 컴포넌트/액션
|
|
import { getBills } from './actions';
|
|
import { BillDetail } from './BillDetail';
|
|
|
|
// 6. 유틸/훅/타입
|
|
import { formatNumber } from '@/lib/utils/amount';
|
|
import type { BillRecord } from './types';
|
|
```
|
|
|
|
### 경로 별칭
|
|
- `@/` = `src/` (tsconfig paths)
|
|
- 항상 `@/` 별칭 사용, 상대 경로(`../../`)는 같은 폴더 내에서만
|
|
|
|
---
|
|
|
|
## 4. 컴포넌트 패턴
|
|
|
|
### 페이지 컴포넌트 (page.tsx)
|
|
|
|
```typescript
|
|
// 얇은 껍데기만 — 비즈니스 로직은 도메인 컴포넌트에
|
|
'use client';
|
|
import { BillManagement } from '@/components/accounting/BillManagement';
|
|
|
|
export default function BillsPage() {
|
|
return <BillManagement />;
|
|
}
|
|
```
|
|
|
|
### 도메인 컴포넌트 (index.tsx)
|
|
|
|
```typescript
|
|
'use client';
|
|
|
|
import { useState, useCallback, useEffect } from 'react';
|
|
// ... imports
|
|
|
|
export function BillManagement() {
|
|
// 1. 상태 선언
|
|
const [data, setData] = useState<BillRecord[]>([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
// 2. 데이터 로드
|
|
const loadData = useCallback(async () => { ... }, [deps]);
|
|
useEffect(() => { loadData(); }, [loadData]);
|
|
|
|
// 3. 이벤트 핸들러
|
|
const handleSave = useCallback(async () => { ... }, [deps]);
|
|
const handleDelete = useCallback(async () => { ... }, [deps]);
|
|
|
|
// 4. 계산값 (useMemo)
|
|
const config = useMemo(() => ({ ... }), [deps]);
|
|
|
|
// 5. 렌더링
|
|
return <UniversalListPage config={config} />;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. TypeScript 규칙
|
|
|
|
### 타입 정의
|
|
|
|
```typescript
|
|
// ✅ 컴포넌트 props는 interface (확장 가능)
|
|
interface BillDetailProps {
|
|
record: BillRecord;
|
|
onSave: (data: BillFormData) => Promise<void>;
|
|
}
|
|
|
|
// ✅ 데이터 모델은 type (유니온/인터섹션 활용)
|
|
type BillStatus = 'draft' | 'confirmed' | 'paid';
|
|
|
|
// ✅ API 응답 변환
|
|
interface BillApiResponse { ... } // 백엔드 스네이크_케이스
|
|
interface BillRecord { ... } // 프론트 camelCase
|
|
function transformBillApiToFrontend(api: BillApiResponse): BillRecord { ... }
|
|
```
|
|
|
|
### 금지 패턴
|
|
|
|
```typescript
|
|
// ❌ any 사용 금지
|
|
const data: any = response;
|
|
|
|
// ❌ as 캐스트 지양 (Zod 사용 시 불필요)
|
|
const value = input as string;
|
|
|
|
// ❌ non-null assertion 지양
|
|
const name = user!.name;
|
|
```
|
|
|
|
---
|
|
|
|
## 6. 상태 관리 규칙
|
|
|
|
| 범위 | 방법 |
|
|
|------|------|
|
|
| 컴포넌트 내부 | useState, useReducer |
|
|
| 형제 간 공유 | 부모에서 prop 전달 |
|
|
| 전역 인증 | useAuthGuard (Context) |
|
|
| 서버 데이터 | Server Action + useState |
|
|
| 대시보드 갱신 | dashboard-invalidation (CustomEvent) |
|
|
|
|
**사용하지 않는 것**: Redux, Zustand, Recoil 등 전역 상태 라이브러리
|
|
|
|
---
|
|
|
|
## 7. 에러 처리 규칙
|
|
|
|
```typescript
|
|
// Server Action 결과 처리
|
|
const result = await saveItem(formData);
|
|
if (result.success) {
|
|
toast.success('저장되었습니다.');
|
|
loadData();
|
|
} else {
|
|
toast.error(result.error || '저장에 실패했습니다.');
|
|
}
|
|
|
|
// try-catch (Server Action 호출 자체의 에러)
|
|
try {
|
|
const result = await getItems();
|
|
if (result.success) setData(result.data);
|
|
} catch {
|
|
toast.error('서버 오류가 발생했습니다.');
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 8. 성능 규칙
|
|
|
|
| 규칙 | 이유 |
|
|
|------|------|
|
|
| `useMemo`로 config 객체 감싸기 | 불필요한 리렌더 방지 |
|
|
| `useCallback`으로 핸들러 감싸기 | 자식 컴포넌트 리렌더 방지 |
|
|
| 무거운 컴포넌트 `React.memo` | 부모 리렌더 시 불필요한 재계산 방지 |
|
|
| 대시보드 섹션 LazySection | Intersection Observer 기반 지연 로딩 |
|
|
| 이미지 `next/image` 사용 | 자동 최적화 |
|
|
|
|
---
|
|
|
|
## 9. Git 커밋 메시지
|
|
|
|
```
|
|
[타입]: 작업내용 (한글)
|
|
|
|
타입:
|
|
- feat: 신규 기능
|
|
- fix: 버그 수정
|
|
- refactor: 리팩토링
|
|
- chore: 설정/빌드
|
|
- style: 포맷팅
|
|
- docs: 문서
|
|
```
|
|
|
|
예시:
|
|
```
|
|
feat: CEO 대시보드 접대비 섹션 API 연동
|
|
fix: 어음관리 날짜 필터 오류 수정
|
|
refactor: 계정과목 설정 모달 공통화
|
|
```
|
|
|
|
---
|
|
|
|
## 10. 빠른 참조
|
|
|
|
| 상황 | 해야 할 것 |
|
|
|------|-----------|
|
|
| 새 리스트 페이지 | UniversalListPage + actions.ts + types.ts |
|
|
| 새 폼 | Zod 스키마 + FormField + react-hook-form |
|
|
| 모달 필요 | SearchableSelectionModal 먼저 확인 |
|
|
| API 호출 | Server Action → buildApiUrl → executeServerAction |
|
|
| 토스트 알림 | `toast.success()` / `toast.error()` |
|
|
| 날짜 입력 | DatePicker (input type="date" 금지) |
|
|
| 대시보드 갱신 | `invalidateDashboard('domain')` |
|
|
| 금액 표시 | `formatNumber()` |
|