최근 많은 프로젝트들을 접하고, 처음에 불편하다고 생각했던 디렉토리구조에 익숙해지다보니 불편함을 잊고 일을하게된다.
다시한번 나만의 프로젝트 구조기준을 정하고, 사이드프로젝트나 혹은 지금 프로젝트를 개선할 수 있는 기회가생겼을때 이 기준으로 진행하면 좋을 것 같다. 물론 이러한 기준은 잘 정리해둔다면 rule 로 만들어 agent에 학습시켜 AI에게 시키기도 좋을 것 같다.
여러 고민들이 있었다.
useAppStore 와 같은 hook 이름 말미에 Store 와 같은 키워드를 붙이는 방향으로 컨벤션을 정해서 사용하면 store라는 별도의 디렉토리를 추가하지 않고도 store를 이쁘게 분류할 수 있다.libs 와 공존하는 프로젝트들을 많이 봐왔는데, 개인적으로 차라리 구분하지않는게 나을 것 같다. 너무 성격이 비슷하고 오히려 구분할때 헷갈린다.이러한 생각과 고민들을 LLM 과 논의하며 readme를 작성해봤다.
꽤나 맘에 들고, 마스카라를 사용하여 최대한 AI 친화적인 프롬프트를 만들어서 cursor 나 windsurf 같은 에이전트에 학습시켜서, 작업중이 사이드프로젝트를 리펙토링 하고, 추후에 다른 멤버가 합류하거나, 기획자들또한 편리하게 프로젝트에 기능을 추가/유지보수할수있도록 개선해야겠다.
이 문서는 프로젝트의 디렉토리 구조와 컴포넌트 설계 철학에 대해 설명합니다.
구조화된 디렉토리는 유지보수와 협업을 원활하게 하고, 확장성과 가독성을 높이는 데 기여합니다.
src/
├── components/ # Atomic Design 기반 공용 컴포넌트
├── pages/ # 실제 라우팅에 대응되는 화면
├── apis/ # API 요청 로직
├── hooks/ # 전역 공통 Hook
├── types/ # 전역 타입 정의
├── utils/ # 프레임워크에 독립적인 순수 유틸 함수
└── theme/ # 스타일 관련 테마 구성
components/
├── atoms/
├── molecules/
├── organisms/
└── layout/
Button, Input, Icon, Typographyatoms/
└── Logo/
├── Logo.tsx
├── Logo.test.tsx
└── Logo.stories.tsx
SearchBar, FormFieldmolecules/
└── SearchBar/
├── SearchBar.tsx
├── SearchBar.test.tsx
└── SearchBar.stories.tsx
💡 내부에 state가 있다고 하더라도, 외부 API나 Context에 의존하지 않는다면 molecule에 속합니다.
UserProfileCard, LoginForm, ProductListorganisms/
└── ProductList/
├── ProductList.tsx
├── ProductList.test.tsx
└── ProductList.stories.tsx
layout/
└── Header/
├── Header.tsx
├── Header.test.tsx
└── Header.stories.tsx
pages/
└── products/
├── index.tsx
├── _components/
│ └── ProductItem.tsx
├── _hooks/
│ └── useFetchProducts.ts
└── _types.ts
_components,_hooks,_types처럼 언더스코어 접두어를 사용해 라우트와 혼동 방지
<endpoint>.schema.ts로 분리apis/
└── product/
├── getList.ts
├── getList.schema.ts
├── getDetail.ts
├── getDetail.schema.ts
└── index.ts
💡 endpoint 기준 분리는 Git 충돌 최소화 및 추적 편의성에 유리
useXxxStore.ts 형태로 명명)hooks/
├── useDebounce.ts
├── useModal.ts
└── useAppStore.ts # 상태 관리 스토어를 캡슐화한 훅
store/ 디렉토리를 만들지 않고, hooks/ 내에 useXxxStore.ts 형태로 관리Store 키워드를 포함 (예: useAppStore, useAuthStore)// hooks/useAppStore.ts 예시
import create from 'zustand'; // 또는 다른 상태 관리 라이브러리
// 1. 스토어 타입 정의
type AppStore = {
count: number;
increment: () => void;
decrement: () => void;
};
// 2. 스토어 내부 구현 (비공개)
const appStore = create<AppStore>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
// 3. 외부에 노출되는 훅 (공개 API)
export const useAppStore = () => {
const { count, increment, decrement } = appStore();
return {
count,
increment,
decrement,
};
};
이 패턴의 장점:
apis/*.schema.ts에서 export 가능types/
├── product.ts # 도메인 타입
├── user.ts
└── global.ts # 공통 타입
libs와 구분하지 않고 하나로 관리utils/
├── date.ts
└── formatter.ts
theme/
├── palette.ts
├── typography.ts
└── theme.ts
아니요. 내부 상태가 있어도 외부에 의존하지 않고, 단순 UI 렌더링에 국한된다면 molecule입니다.
예:ToggleSwitch,TabPanel등
이 가이드는 프로젝트 상황에 따라 유연하게 확장할 수 있으며,
명확한 기준을 통해 일관된 코드베이스를 유지하는 데 목적이 있습니다.