Files
sam-design/src/DEVELOPMENT_GUIDELINES.md

1120 lines
25 KiB
Markdown
Raw Normal View History

# 📘 SAM MES 솔루션 개발 가이드라인
## 📋 목차
1. [시작하기](#시작하기)
2. [프로젝트 구조](#프로젝트-구조)
3. [코딩 규칙](#코딩-규칙)
4. [컴포넌트 개발](#컴포넌트-개발)
5. [스타일링 가이드](#스타일링-가이드)
6. [TypeScript 가이드](#typescript-가이드)
7. [상태 관리](#상태-관리)
8. [파일 명명 규칙](#파일-명명-규칙)
9. [Git 워크플로우](#git-워크플로우)
10. [테스팅](#테스팅)
11. [성능 최적화](#성능-최적화)
12. [접근성](#접근성)
13. [보안](#보안)
14. [문서화](#문서화)
15. [베스트 프랙티스](#베스트-프랙티스)
---
## 🚀 시작하기
### **프로젝트 개요**
SAM MES는 중소 및 중견기업을 위한 완전한 제조실행시스템(MES) 솔루션입니다.
### **핵심 기술**
- React 18+ (TypeScript)
- Tailwind CSS v4.0
- shadcn/ui 컴포넌트
- Recharts (데이터 시각화)
- Figma Make 플랫폼
### **개발 환경 설정**
1. 프로젝트 파일 구조 파악
2. `TECH_STACK.md` 문서 읽기
3. `DEVELOPMENT_ENVIRONMENT.md` 문서 읽기
4. 기존 컴포넌트 코드 분석
---
## 📁 프로젝트 구조
### **디렉토리 구조**
```
SAM-MES/
├── App.tsx # 메인 애플리케이션 엔트리
├── *.md # 프로젝트 문서들
├── components/ # React 컴포넌트
│ ├── [PageComponents].tsx # 페이지 레벨 컴포넌트 (30+)
│ ├── ui/ # shadcn/ui 컴포넌트 (53개)
│ │ ├── button.tsx
│ │ ├── dialog.tsx
│ │ ├── table.tsx
│ │ └── ...
│ └── figma/ # Figma 전용 컴포넌트
│ └── ImageWithFallback.tsx # 이미지 폴백 처리
├── styles/
│ └── globals.css # 글로벌 스타일 & 테마
├── guidelines/
│ └── Guidelines.md # 추가 가이드라인
└── [scripts].js # 유틸리티 스크립트
```
### **컴포넌트 분류**
#### **1. 페이지 컴포넌트** (`components/`)
- `Dashboard.tsx` - CEO 대시보드
- `SalesManagement.tsx` - 판매관리
- `ProductionManagement.tsx` - 생산관리 (최대 규모)
- `QualityManagement.tsx` - 품질관리
- `MaterialManagement.tsx` - 자재관리
- `ShippingManagement.tsx` - 출고관리
- `HRManagement.tsx` - 인사관리
- `ApprovalManagement.tsx` - 전자결재
- `AccountingManagement.tsx` - 회계관리
- `MasterData.tsx` - 기준정보
- 등 30+ 컴포넌트
#### **2. UI 컴포넌트** (`components/ui/`)
- 53개의 재사용 가능한 UI 컴포넌트
- shadcn/ui 기반
- **수정 금지** (새로운 컴포넌트 생성 시에만)
#### **3. 특수 컴포넌트** (`components/figma/`)
- `ImageWithFallback.tsx` - 이미지 로딩 및 폴백
- **수정 금지** (시스템 보호 파일)
---
## 📝 코딩 규칙
### **1. 일반 원칙**
```typescript
// ✅ DO: 명확하고 읽기 쉬운 코드
function calculateTotalPrice(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// ❌ DON'T: 불명확한 변수명과 로직
function calc(arr: any[]): any {
return arr.reduce((a, b) => a + b.p, 0);
}
```
### **2. 코드 포맷팅**
```typescript
// 들여쓰기: 2 스페이스
// 세미콜론: 사용
// 따옴표: 쌍따옴표 우선
// 줄 길이: 최대 100자 권장
export function MyComponent({ title, description }: Props) {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="p-4">
<h1>{title}</h1>
<p>{description}</p>
</div>
);
}
```
### **3. Import 순서**
```typescript
// 1. React 관련
import { useState, useEffect } from "react";
// 2. UI 컴포넌트 (shadcn/ui)
import { Button } from "./ui/button";
import { Dialog, DialogContent } from "./ui/dialog";
import { Card, CardContent, CardHeader } from "./ui/card";
// 3. 아이콘
import { Plus, Edit, Trash2 } from "lucide-react";
// 4. 외부 라이브러리
import { format } from "date-fns";
import { ko } from "date-fns/locale";
import { BarChart, Bar } from "recharts";
// 5. 타입 정의
interface Props {
title: string;
}
```
---
## 🎨 컴포넌트 개발
### **1. 컴포넌트 구조**
```typescript
import { useState } from "react";
import { Button } from "./ui/button";
// Props 타입 정의
interface MyComponentProps {
title: string;
onSave?: () => void;
}
// 컴포넌트 선언
export function MyComponent({ title, onSave }: MyComponentProps) {
// 1. State 선언
const [data, setData] = useState<string[]>([]);
const [isLoading, setIsLoading] = useState(false);
// 2. 핸들러 함수
const handleClick = () => {
console.log("Clicked");
onSave?.();
};
// 3. useEffect (필요시)
useEffect(() => {
// 초기 데이터 로드
}, []);
// 4. 조건부 렌더링
if (isLoading) {
return <div>Loading...</div>;
}
// 5. JSX 반환
return (
<div className="p-4">
<h1>{title}</h1>
<Button onClick={handleClick}>저장</Button>
</div>
);
}
```
### **2. 페이지 컴포넌트 템플릿**
```typescript
import { useState } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
import { Button } from "./ui/button";
import { Plus, Download } from "lucide-react";
export function MyPage() {
const [activeTab, setActiveTab] = useState("list");
return (
<div className="min-h-screen bg-background p-4 md:p-6 lg:p-8">
{/* 헤더 */}
<div className="bg-card border border-border/20 rounded-xl p-6 mb-8">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
<div>
<h1 className="text-3xl font-bold text-foreground mb-2">페이지 제목</h1>
<p className="text-muted-foreground">페이지 설명</p>
</div>
<div className="flex space-x-3">
<Button variant="outline">
<Download className="h-4 w-4 mr-2" />
내보내기
</Button>
<Button>
<Plus className="h-4 w-4 mr-2" />
추가
</Button>
</div>
</div>
</div>
{/* 메인 콘텐츠 */}
<Card>
<CardHeader>
<CardTitle>섹션 제목</CardTitle>
</CardHeader>
<CardContent>
{/* 내용 */}
</CardContent>
</Card>
</div>
);
}
```
### **3. 반응형 컴포넌트 패턴**
```typescript
// 데스크톱: 테이블 / 모바일: 카드
export function ResponsiveList({ items }: Props) {
return (
<>
{/* 데스크톱 테이블 (hidden on mobile) */}
<div className="hidden md:block">
<Table>
<TableHeader>
<TableRow>
<TableHead>이름</TableHead>
<TableHead>상태</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{items.map((item) => (
<TableRow key={item.id}>
<TableCell>{item.name}</TableCell>
<TableCell>{item.status}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
{/* 모바일 카드 (visible on mobile) */}
<div className="md:hidden space-y-4">
{items.map((item) => (
<Card key={item.id}>
<CardContent className="p-4">
<div className="font-semibold">{item.name}</div>
<div className="text-sm text-muted-foreground">{item.status}</div>
</CardContent>
</Card>
))}
</div>
</>
);
}
```
---
## 🎨 스타일링 가이드
### **1. Tailwind CSS 기본 원칙**
#### **✅ DO: Tailwind 유틸리티 클래스 사용**
```typescript
<div className="flex items-center justify-between p-4 bg-card rounded-lg border border-border">
<h2 className="text-xl text-foreground">제목</h2>
<Button variant="outline" size="sm">버튼</Button>
</div>
```
#### **❌ DON'T: 인라인 스타일 사용**
```typescript
// 피하기
<div style={{ display: "flex", padding: "16px" }}>
```
### **2. 색상 사용**
```typescript
// ✅ CSS 변수 사용 (테마 대응)
className="bg-primary text-primary-foreground"
className="bg-card text-card-foreground"
className="bg-destructive text-destructive-foreground"
className="border-border"
className="text-muted-foreground"
// ❌ 하드코딩된 색상 (피하기)
className="bg-blue-500 text-white"
```
### **3. 반응형 디자인**
```typescript
// Mobile First 접근
className="
p-4 // 모바일: 16px padding
md:p-6 // 태블릿: 24px padding
lg:p-8 // 데스크톱: 32px padding
flex-col // 모바일: 세로 방향
md:flex-row // 태블릿+: 가로 방향
text-sm // 모바일: 작은 텍스트
md:text-base // 태블릿+: 기본 크기
"
```
### **4. 간격 시스템**
```typescript
// Spacing Scale (4px 단위)
className="p-2" // 8px
className="p-4" // 16px
className="p-6" // 24px
className="p-8" // 32px
className="gap-2" // 8px
className="gap-4" // 16px
className="gap-6" // 24px
```
### **5. 폰트 크기/굵기 사용 제한**
```typescript
// ⚠️ 주의: 폰트 크기, 굵기, 라인 높이는 기본값 사용
// globals.css에 정의된 기본 스타일 활용
// ❌ 피하기 (특별한 요구사항 없으면)
className="text-2xl font-bold leading-tight"
// ✅ 권장 (기본값 사용)
<h1>제목</h1> // globals.css의 h1 스타일 자동 적용
<p>내용</p> // globals.css의 p 스타일 자동 적용
```
---
## 📘 TypeScript 가이드
### **1. 타입 정의**
#### **Interface vs Type**
```typescript
// ✅ Props는 interface 사용 (확장 가능)
interface ButtonProps {
label: string;
onClick?: () => void;
variant?: "primary" | "secondary";
}
// ✅ 유니온 타입은 type 사용
type Status = "active" | "inactive" | "pending";
// ✅ 복잡한 타입은 type 사용
type ComplexType = {
id: string;
data: Record<string, unknown>;
} & BaseType;
```
#### **타입 재사용**
```typescript
// 공통 타입 정의
interface BaseEntity {
id: string;
createdAt: string;
updatedAt: string;
}
interface Product extends BaseEntity {
name: string;
price: number;
}
interface Order extends BaseEntity {
productId: string;
quantity: number;
}
```
### **2. 타입 안정성**
#### **✅ DO: 명시적 타입 지정**
```typescript
// State 타입 명시
const [items, setItems] = useState<Product[]>([]);
const [selectedId, setSelectedId] = useState<string | null>(null);
// 함수 매개변수 타입 명시
function calculateTotal(items: Product[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// 이벤트 핸들러 타입
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
console.log(event.currentTarget);
};
```
#### **❌ DON'T: any 타입 사용**
```typescript
// ❌ 피하기
const [data, setData] = useState<any>([]);
function process(input: any): any { }
// ✅ 대신 사용
const [data, setData] = useState<unknown[]>([]);
function process(input: unknown): Result { }
```
### **3. 옵셔널 체이닝 & Nullish Coalescing**
```typescript
// ✅ 옵셔널 체이닝
const userName = user?.profile?.name;
// ✅ Nullish Coalescing
const displayName = user?.name ?? "Guest";
// ✅ 옵셔널 콜백
onSave?.();
```
---
## 🔄 상태 관리
### **1. useState 패턴**
```typescript
// ✅ 단순 상태
const [isOpen, setIsOpen] = useState(false);
const [count, setCount] = useState(0);
// ✅ 객체 상태 (불변성 유지)
const [user, setUser] = useState({ name: "", email: "" });
const updateName = (newName: string) => {
setUser(prev => ({ ...prev, name: newName }));
};
// ✅ 배열 상태
const [items, setItems] = useState<Item[]>([]);
const addItem = (item: Item) => {
setItems(prev => [...prev, item]);
};
const removeItem = (id: string) => {
setItems(prev => prev.filter(item => item.id !== id));
};
```
### **2. useEffect 패턴**
```typescript
// ✅ 컴포넌트 마운트 시 1회 실행
useEffect(() => {
// 초기 데이터 로드
fetchData();
}, []); // 빈 의존성 배열
// ✅ 특정 값 변경 시 실행
useEffect(() => {
if (selectedId) {
loadDetails(selectedId);
}
}, [selectedId]); // selectedId 변경 감지
// ✅ 클린업 함수
useEffect(() => {
const timer = setInterval(() => {
// 주기적 작업
}, 1000);
return () => {
clearInterval(timer); // 컴포넌트 언마운트 시 정리
};
}, []);
```
### **3. 로컬 상태 vs Props**
```typescript
// ✅ 로컬에서만 사용되는 UI 상태
const [isHovered, setIsHovered] = useState(false);
const [isMenuOpen, setIsMenuOpen] = useState(false);
// ✅ 부모로부터 받는 데이터
interface Props {
data: Product[]; // 읽기 전용 데이터
onUpdate: () => void; // 상태 변경은 부모가 처리
}
```
---
## 📂 파일 명명 규칙
### **1. 컴포넌트 파일**
```
PascalCase.tsx
├── Dashboard.tsx
├── SalesManagement.tsx
├── ProductionManagement.tsx
└── UserProfile.tsx
```
### **2. UI 컴포넌트 (shadcn/ui)**
```
kebab-case.tsx
├── button.tsx
├── dialog.tsx
├── table.tsx
└── dropdown-menu.tsx
```
### **3. 유틸리티 파일**
```
camelCase.ts / kebab-case.ts
├── utils.ts
├── helpers.ts
└── use-mobile.ts
```
### **4. 문서 파일**
```
UPPER_CASE.md / PascalCase.md
├── README.md
├── TECH_STACK.md
├── DEVELOPMENT_ENVIRONMENT.md
└── Guidelines.md
```
### **5. 스타일 파일**
```
kebab-case.css / lowercase.css
├── globals.css
└── custom-styles.css
```
---
## 🔀 Git 워크플로우
### **1. 브랜치 전략**
```bash
main # 프로덕션 브랜치
├── develop # 개발 브랜치
├── feature/* # 기능 개발
├── bugfix/* # 버그 수정
└── hotfix/* # 긴급 수정
```
### **2. 커밋 메시지 규칙**
```bash
# 형식: <타입>: <제목>
feat: 판매관리 견적 산출 기능 추가
fix: 생산관리 모달 스크롤 오류 수정
style: Dashboard 레이아웃 개선
refactor: MaterialManagement 컴포넌트 리팩토링
docs: README 업데이트
test: QualityManagement 테스트 추가
chore: 의존성 업데이트
```
### **3. 커밋 타입**
- `feat`: 새로운 기능
- `fix`: 버그 수정
- `style`: UI/스타일 변경
- `refactor`: 코드 리팩토링
- `docs`: 문서 수정
- `test`: 테스트 추가/수정
- `chore`: 빌드, 설정 등
---
## 🧪 테스팅
### **1. 컴포넌트 테스트 체크리스트**
```typescript
// 수동 테스트 체크리스트
// [ ] 컴포넌트가 정상적으로 렌더링되는가?
// [ ] Props가 올바르게 전달되는가?
// [ ] 이벤트 핸들러가 작동하는가?
// [ ] 조건부 렌더링이 올바른가?
// [ ] 에러 상태가 처리되는가?
// [ ] 로딩 상태가 표시되는가?
```
### **2. 반응형 테스트**
```
브레이크포인트 테스트:
[ ] Mobile (< 768px)
[ ] Tablet (768px - 1024px)
[ ] Desktop (> 1024px)
기기별 테스트:
[ ] iPhone (Safari)
[ ] Android (Chrome)
[ ] iPad (Safari)
[ ] Desktop (Chrome, Firefox, Safari)
```
### **3. 브라우저 호환성**
```
[ ] Chrome (최신)
[ ] Firefox (최신)
[ ] Safari (최신)
[ ] Edge (최신)
```
---
## ⚡ 성능 최적화
### **1. 리렌더링 최적화**
```typescript
// ✅ useMemo - 비용이 큰 계산 메모이제이션
const expensiveValue = useMemo(() => {
return items.reduce((sum, item) => sum + item.price, 0);
}, [items]);
// ✅ useCallback - 함수 메모이제이션
const handleClick = useCallback((id: string) => {
console.log("Clicked:", id);
}, []);
// ✅ React.memo - 컴포넌트 메모이제이션
export const MemoizedComponent = memo(function MyComponent({ data }: Props) {
return <div>{data}</div>;
});
```
### **2. 조건부 렌더링**
```typescript
// ✅ 불필요한 컴포넌트 렌더링 방지
{isVisible && <ExpensiveComponent />}
// ✅ 로딩 상태
{isLoading ? <Skeleton /> : <Content />}
```
### **3. 이미지 최적화**
```typescript
// ✅ ImageWithFallback 컴포넌트 사용
import { ImageWithFallback } from "./components/figma/ImageWithFallback";
<ImageWithFallback
src={imageUrl}
alt="제품 이미지"
className="w-full h-auto"
/>
```
---
## ♿ 접근성 (Accessibility)
### **1. 시맨틱 HTML**
```typescript
// ✅ 의미있는 HTML 태그 사용
<header>
<nav>
<ul>
<li><a href="/"></a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>제목</h1>
<p>내용</p>
</article>
</main>
<footer>
<p>Copyright 2025</p>
</footer>
```
### **2. ARIA 속성**
```typescript
// ✅ 스크린 리더를 위한 레이블
<button aria-label="메뉴 열기">
<Menu />
</button>
// ✅ 상태 표시
<div role="alert" aria-live="polite">
저장되었습니다.
</div>
// ✅ 숨김 콘텐츠
<DialogTitle className="sr-only">대화상자 제목</DialogTitle>
```
### **3. 키보드 네비게이션**
```typescript
// ✅ Tab 키로 이동 가능
<button>클릭 가능</button>
<a href="/page">링크</a>
// ✅ Enter/Space로 활성화
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === "Enter" || e.key === " ") {
handleClick();
}
};
```
---
## 🔒 보안
### **1. XSS 방지**
```typescript
// ✅ React는 기본적으로 XSS 방지
<div>{userInput}</div> // 자동 이스케이프
// ❌ dangerouslySetInnerHTML 사용 금지 (특별한 경우 제외)
<div dangerouslySetInnerHTML={{ __html: content }} />
```
### **2. 민감 정보 처리**
```typescript
// ❌ 클라이언트 코드에 민감 정보 하드코딩 금지
const API_KEY = "secret-key-123"; // 절대 금지!
// ✅ 환경 변수 사용 또는 서버사이드 처리
const API_URL = process.env.VITE_API_URL;
```
### **3. 입력 검증**
```typescript
// ✅ 사용자 입력 검증
const validateEmail = (email: string): boolean => {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
};
const handleSubmit = (email: string) => {
if (!validateEmail(email)) {
alert("올바른 이메일을 입력하세요.");
return;
}
// 처리
};
```
---
## 📚 문서화
### **1. 컴포넌트 문서화**
```typescript
/**
* 사용자 프로필 카드 컴포넌트
*
* @param {string} name - 사용자 이름
* @param {string} email - 사용자 이메일
* @param {() => void} onEdit - 편집 버튼 클릭 핸들러
*
* @example
* <UserProfileCard
* name="홍길동"
* email="hong@example.com"
* onEdit={() => console.log("edit")}
* />
*/
export function UserProfileCard({ name, email, onEdit }: UserProfileCardProps) {
// ...
}
```
### **2. 복잡한 로직 주석**
```typescript
// ✅ 복잡한 비즈니스 로직에 주석 추가
function calculateDiscount(price: number, quantity: number): number {
// 10개 이상 구매 시 10% 할인
// 50개 이상 구매 시 20% 할인
// 100개 이상 구매 시 30% 할인
if (quantity >= 100) {
return price * 0.7;
} else if (quantity >= 50) {
return price * 0.8;
} else if (quantity >= 10) {
return price * 0.9;
}
return price;
}
```
### **3. TODO 주석**
```typescript
// TODO: 성능 최적화 필요
// FIXME: 특정 조건에서 버그 발생
// HACK: 임시 해결책, 추후 개선 필요
// NOTE: 중요한 정보 또는 주의사항
```
---
## ✨ 베스트 프랙티스
### **1. DRY (Don't Repeat Yourself)**
```typescript
// ❌ 중복 코드
function formatUserName1(name: string) {
return name.trim().toUpperCase();
}
function formatProductName(name: string) {
return name.trim().toUpperCase();
}
// ✅ 재사용 가능한 함수
function formatName(name: string): string {
return name.trim().toUpperCase();
}
const userName = formatName(user.name);
const productName = formatName(product.name);
```
### **2. 단일 책임 원칙**
```typescript
// ❌ 하나의 컴포넌트가 너무 많은 역할
function ComplexComponent() {
// 데이터 로딩
// 폼 처리
// 차트 렌더링
// 테이블 렌더링
// ... 1000+ 줄
}
// ✅ 책임 분리
function DataContainer() {
return (
<>
<DataForm />
<DataChart />
<DataTable />
</>
);
}
```
### **3. 명확한 변수명**
```typescript
// ❌ 불명확한 이름
const d = new Date();
const arr = [...items];
const temp = x * y;
// ✅ 명확한 이름
const currentDate = new Date();
const sortedItems = [...items];
const totalPrice = quantity * unitPrice;
```
### **4. Early Return 패턴**
```typescript
// ❌ 중첩된 조건문
function processUser(user: User) {
if (user) {
if (user.isActive) {
if (user.hasPermission) {
// 처리
}
}
}
}
// ✅ Early Return
function processUser(user: User) {
if (!user) return;
if (!user.isActive) return;
if (!user.hasPermission) return;
// 처리
}
```
### **5. 에러 처리**
```typescript
// ✅ Try-Catch로 에러 처리
async function fetchData() {
try {
const response = await fetch("/api/data");
const data = await response.json();
return data;
} catch (error) {
console.error("데이터 로드 실패:", error);
return null;
}
}
// ✅ 에러 상태 표시
const [error, setError] = useState<string | null>(null);
{error && (
<Alert variant="destructive">
<AlertTitle>오류</AlertTitle>
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
```
---
## 🚨 일반적인 실수 & 해결책
### **1. Key Props 누락**
```typescript
// ❌ key 없이 리스트 렌더링
{items.map(item => <div>{item.name}</div>)}
// ✅ 고유한 key 사용
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
```
### **2. State 직접 수정**
```typescript
// ❌ State 직접 수정
const [items, setItems] = useState([]);
items.push(newItem); // 금지!
// ✅ 새로운 배열 생성
setItems([...items, newItem]);
setItems(prev => [...prev, newItem]);
```
### **3. useEffect 의존성 배열 누락**
```typescript
// ❌ 의존성 배열 누락
useEffect(() => {
fetchData(userId);
}); // 무한 루프!
// ✅ 의존성 명시
useEffect(() => {
fetchData(userId);
}, [userId]);
```
### **4. 불필요한 리렌더링**
```typescript
// ❌ 매번 새로운 객체 생성
<Component style={{ margin: 10 }} />
// ✅ 상수로 분리
const componentStyle = { margin: 10 };
<Component style={componentStyle} />
```
---
## 📋 체크리스트
### **코드 리뷰 전 체크리스트**
```
코드 품질:
[ ] TypeScript 타입 오류 없음
[ ] ESLint 경고 없음
[ ] 불필요한 console.log 제거
[ ] 주석 작성 (복잡한 로직)
[ ] 변수명이 명확함
기능:
[ ] 요구사항 모두 구현
[ ] 에러 처리 구현
[ ] 로딩 상태 구현
[ ] 엣지 케이스 처리
UI/UX:
[ ] 반응형 디자인 동작
[ ] 모바일/데스크톱 테스트
[ ] 접근성 준수
[ ] 키보드 네비게이션 가능
성능:
[ ] 불필요한 리렌더링 없음
[ ] 큰 리스트 최적화
[ ] 이미지 최적화
[ ] 번들 크기 확인
문서화:
[ ] README 업데이트 (필요시)
[ ] 변경 사항 기록
[ ] API 문서 업데이트 (필요시)
```
### **배포 전 체크리스트**
```
[ ] 모든 테스트 통과
[ ] 브라우저 호환성 확인
[ ] 성능 측정 완료
[ ] 보안 취약점 점검
[ ] 백업 완료
[ ] 롤백 계획 수립
```
---
## 🎓 학습 리소스
### **필수 문서**
1. `TECH_STACK.md` - 기술 스택
2. `DEVELOPMENT_ENVIRONMENT.md` - 개발 환경
3. `guidelines/Guidelines.md` - 추가 가이드
### **공식 문서**
- [React 공식 문서](https://react.dev/)
- [TypeScript 핸드북](https://www.typescriptlang.org/docs/)
- [Tailwind CSS 문서](https://tailwindcss.com/docs)
- [shadcn/ui 문서](https://ui.shadcn.com/)
### **추천 학습 경로**
1. **1주차**: React & TypeScript 기초
2. **2주차**: Tailwind CSS & shadcn/ui
3. **3주차**: 프로젝트 구조 파악
4. **4주차**: 실제 컴포넌트 개발
---
## 🎯 핵심 원칙 요약
### **코드 작성 원칙**
1. **타입 안정성**: 모든 코드에 TypeScript 타입 적용
2. **재사용성**: DRY 원칙 준수, 공통 컴포넌트 활용
3. **가독성**: 명확한 변수명, 적절한 주석
4. **성능**: 불필요한 리렌더링 방지
5. **접근성**: 모든 사용자가 사용 가능하도록
### **UI/UX 원칙**
1. **반응형**: 모든 화면 크기 대응
2. **일관성**: 디자인 시스템 준수
3. **피드백**: 로딩, 에러, 성공 상태 표시
4. **접근성**: 키보드, 스크린 리더 지원
### **협업 원칙**
1. **문서화**: 코드와 변경사항 문서화
2. **커뮤니케이션**: 불확실한 부분 질문
3. **코드 리뷰**: 건설적인 피드백
4. **지식 공유**: 학습 내용 팀과 공유
---
## 📞 도움 받기
### **질문하기 전 체크**
1. 공식 문서 확인
2. 기존 코드 참고
3. 에러 메시지 검색
### **질문 형식**
```
제목: [컴포넌트명] 간단한 문제 설명
환경:
- 파일: components/MyComponent.tsx
- 브라우저: Chrome 120
문제:
[상세한 문제 설명]
시도한 해결책:
1. ...
2. ...
에러 메시지:
[에러 메시지 복사]
```
---
## 🎉 결론
이 가이드라인은 **SAM MES 솔루션** 개발의 기준이 됩니다.
**핵심 포인트**:
✅ TypeScript로 타입 안정성 확보
✅ Tailwind CSS로 일관된 스타일링
✅ 반응형 디자인으로 모든 기기 지원
✅ shadcn/ui로 빠른 개발
✅ 베스트 프랙티스 준수
이 가이드를 따르면 높은 품질의 코드를 작성하고 유지보수가 쉬운 시스템을 구축할 수 있습니다.
---
**문서 작성일**: 2025년 10월 17일
**버전**: 1.0.0
**작성자**: SAM MES 개발팀
**Happy Coding! 🚀**