AX CENTER
개발자 가이드
이 프로젝트의 디자인 시스템 사용법, API 연동 방식, 코딩 컨벤션을 설명합니다. 작업 전 반드시 숙지해 주세요.
1
디자인 시스템
타이포그래피
모든 텍스트는 globals.css에 정의된 유틸리티 클래스를 사용합니다. 직접적인 font-size / font-weight 지정은 금지합니다.
txt-h144→60px · BoldHero 대제목txt-h240→54px · BoldHero 소제목txt-t136→40px · Bold섹션 제목txt-t228→32px · Bold서브 섹션txt-t324→28px · Bold카드 제목txt-st-bold20→24px · Bold강조 본문txt-st-regular20→24px · Regular일반 본문txt-b-bold14→16px · Bold작은 강조txt-b-regular14→16px · Regular작은 본문txt-c1-bold12→14px · Bold캡션 강조txt-c1-regular12→14px · Regular캡션txt-c2-bold10→12px · Bold극소 강조txt-c2-regular10→12px · Regular극소컬러 토큰
hex 코드 직접 사용 금지. globals.css @theme에 정의된 토큰만 사용합니다.
Grayscale
gray-0
100
200
300
400
500
600
700
800
900
Special Navy (브랜드 주요색)
100
200
300
400
500
600
700
800
900
Blue
100
200
300
400
500
600
700
800
900
디자인 규칙
✅ 허용
<h1 className="txt-h1 text-gray-900">제목</h1>
<p className="txt-b-regular text-gray-500">본문</p>
<div className="bg-special-navy-500 text-white" />❌ 금지
<h1 style={{ fontSize: "60px", fontWeight: 700 }}>제목</h1>
<p className="text-sm text-[#6b6b6b]">본문</p>
<div style={{ backgroundColor: "#383649", color: "#fff" }} />2
서버 API 연동
타입 정의
서버 DTO와 UI 모델을 반드시 분리합니다. 컴포넌트는 DTO를 직접 받지 않습니다.
// src/types/{domain}.ts
/* 백엔드 원본 응답 — Service Layer 외부에서 사용 금지 */
export interface NoticeDTO {
id: number;
title: string;
is_pinned: boolean; // snake_case
created_at: string; // 문자열
}
/* UI가 소비하는 Domain Model */
export interface Notice {
id: number;
title: string;
isPinned: boolean; // camelCase
createdAt: Date; // Date 객체로 변환
}Service Layer
API 호출과 DTO → Domain Model 변환은 반드시 service.ts 에서만 처리합니다.
// src/api/services/notice.service.ts
import { apiFetch } from "@/api/client";
import type { Notice, NoticeDTO } from "@/types/notice";
function mapNoticeDTO(dto: NoticeDTO): Notice {
return {
id: dto.id,
title: dto.title,
isPinned: dto.is_pinned,
createdAt: new Date(dto.created_at),
};
}
export async function getNoticeList(): Promise<Notice[]> {
const dtos = await apiFetch<NoticeDTO[]>("/notices");
return dtos.map(mapNoticeDTO);
}페이지에서 사용
// src/app/notice/page.tsx
import { Suspense } from "react";
import { getNoticeList } from "@/api/services/notice.service";
import { NoticeList } from "@/components/features/notice/NoticeList";
async function NoticeSection() {
const noticeList = await getNoticeList(); // ← Service만 호출
return <NoticeList noticeList={noticeList} />;
}
export default function NoticePage() {
return (
<main>
<Suspense fallback={<NoticeSkeleton />}>
<NoticeSection />
</Suspense>
</main>
);
}✅ 허용
const noticeList = await getNoticeList();
// Notice[] — Domain Model❌ 금지
const res = await fetch("/api/notices");
const data = await res.json();
// DTO를 컴포넌트에 그대로 전달 금지3
컴포넌트 & 코딩 규칙
네이밍
// Boolean: is / has / can 접두사 필수
const isLoading = true;
const hasError = false;
const canSubmit = true;
// Handler: Props는 on, 내부 로직은 handle
interface ButtonProps {
onSubmit: () => void; // Props로 전달받는 경우
}
function Button({ onSubmit }: ButtonProps) {
function handleSubmit() { // 컴포넌트 내부 핸들러
// 전처리 로직...
onSubmit();
}
return <button onClick={handleSubmit} />;
}
// 약어 금지 — 의미가 명확한 이름 사용
const noticeList = ...; // ✅
const data = ...; // ❌리스트 렌더링 key
✅ 허용
{noticeList.map((notice) => (
<li key={notice.id}>
<NoticeCard notice={notice} />
</li>
))}❌ 금지
{noticeList.map((notice, index) => (
<li key={index}> {/* 금지: index는 key 불가 */}
<NoticeCard notice={notice} />
</li>
))}Early Return
✅ 허용
function NoticeList({ noticeList }: NoticeListProps) {
if (noticeList.length === 0) {
return <EmptyState />;
}
return (
<ul>
{noticeList.map((notice) => (
<li key={notice.id}>
<NoticeCard notice={notice} />
</li>
))}
</ul>
);
}❌ 금지
function NoticeList({ noticeList }: NoticeListProps) {
return (
<ul>
{noticeList.length > 0 ? (
noticeList.map((notice, i) => (
<li key={i}>...</li> // depth 중첩 + index key
))
) : (
<EmptyState />
)}
</ul>
);
}파일 구조
src/
├── api/
│ ├── client.ts # apiFetch — HTTP 추상화
│ └── services/
│ └── {domain}.service.ts # DTO → Domain Model 변환
├── app/ # Next.js App Router
│ ├── {route}/
│ │ └── page.tsx
│ └── layout.tsx
├── components/
│ ├── ui/ # 공통 컴포넌트 (Button, Input…)
│ └── features/
│ └── {domain}/ # 도메인별 컴포넌트
│ ├── {Domain}Card.tsx
│ └── {Domain}List.tsx
├── types/
│ ├── common.ts # 공통 타입
│ └── {domain}.ts # DTO + Domain Model
└── utils/
└── format.ts # 순수 유틸 함수