흩어진 메모를 빛나는 결과물로
![]() 조혜린 |
![]() 백지연 |
![]() 최윤하 |
![]() 임서준 |
♟️ GITHUB 전략
브랜치 전략: git flow 기반 + develop 운영
GitHub Flow: 브랜치/규칙이 단순해서 온보딩이 빠르고, 기능 단위로 PR을 올리는 흐름 명확
브랜치 역할
main: 배포 가능 브랜치develop: 기능 브랜치들이 모이는 통합 브랜치
🌳 브랜치 컨벤션
기능명 규칙: 케밥 케이스(kebab-case)
- init/feature-name/#issue-number: 초기 세팅, 환경 구성, 템플릿/룰 셋업 등
- feat/feature-name/#issue-number: 신규 기능 개발
- fix/feature-name/#issue-number: 버그 수정
- refactor/feature-name/#issue-number: 리팩터링(동작 변경 최소화, 구조 개선 중심)
- Docs/feature-name/#issue-number: 문서 작업 (README, 주석, 가이드, 문서 구조 정리 등)
- Perf/feature-name/#issue-number: 성능 개선 (렌더링 최적화, 불필요한 연산 제거, 메모리/속도 개선 등)
➡️ merge가 끝난 브랜치는 반드시 삭제 (squash merge)
📝 PR 컨벤션
PR 단위: 하나의 PR에는 최대한 하나의 기능만 포함
PR 제목: PR 제목은 Type(모노레포 영역) 로 시작하고, Type은 앞 글자 대문자로 통일
- Feat(client): 로그인 기능 추가
- Feat(cds): Button 컴포넌트 구현
- Init(client): router 설정
- Init(project): PR/Issue 템플릿 세팅
- Fix(client): 메모 저장 시 중복 호출 수정
- Refactor(client): API 에러 처리 구조 개선
🖊️ 커밋 컨벤션
init: 커밋 메시지feat: 커밋 메시지fix: 커밋 메시지chore: 커밋 메시지refactor: 커밋 메시지docs: 커밋 메시지perf: 커밋 메시지test: 커밋 메시지
📡 Issue 컨벤션
Issue 제목은 작업 성격을 바로 알 수 있도록 prefix 추가
- [Init] 프로젝트 초기 세팅
- [Feat] Tab 컴포넌트 구현
- [Fix] 색상 수정
- [Refactor] API 모듈 구조 개선
💌 코드리뷰 규칙
merge 조건
- PR은 최소 2명 이상의 Approve가 있어야 merge 가능
- 직접 push로 합치는 방식은 지양,, 반드시 PR을 통해 merge
리뷰 타임
- PR이 올라오면 가능한 빨리 리뷰
- 몰아서 한 번에가 아니라, 올라오는 즉시 분산 리뷰가 원칙
리뷰 기준
- 리뷰 코멘트는 최대한 둥글게 작성
- 근거있는 주장
- 가능한 경우 레퍼런스(문서/가이드/팀 규칙)를 함께 첨부
리뷰에서 중요하게 보는 포인트 예시
- 아키텍처/폴더 구조 일관성
- 예외 처리/에러 핸들링
- 성능에 영향 줄 수 있는 부분(불필요 렌더링, 무거운 연산 등)
- 타입 안정성(TypeScript), API 계약 준수
- 접근성/UX 고려(로딩/에러 상태 등)
- 네이밍/가독성(우리 팀이 중요하게 보는 기준)
🧩 컴포넌트
네이밍
- 리액트 컴포넌트만 PascalCase를 사용
- ex: Header, MemoCard, AiSummaryPanel)
- 그 외 유틸/함수/변수는 camelCase
export 규칙
- 컴포넌트는 기본적으로 default export를 사용
- 모듈 집합(index.ts)에서는 named export로 re-export
JSX 작성 규칙
- 의미 없는 div 남발을 지양하고, 가능한 시맨틱 태그를 사용
- 예: section, header, main, nav, article, aside, footer
- 최상단 래퍼가 의미가 없다면 Fragment(<>...</>)를 사용
- children이 불필요한 컴포넌트는 Self closing
- 예:
<EmptyState />
- 예:
이벤트 핸들러 규칙
- 이벤트 핸들러 함수는 반드시 handle prefix를 사용
- 예: handleSubmit, handleResetClick
📂 폴더명
규칙
- 폴더명은 kebab-case + 소문자 시작
- 예: user-profile, memo-list, error-boundary
- 가능한 경우 복수형(s) 사용
- 예: models, libs, styles, configs
⛓️ 타입
네이밍 규칙
- 타입/인터페이스 이름은 PascalCase를 사용
- 기본적으로 type보다 interface를 우선 사용
Props 네이밍
- Props 타입은 반드시 Props 접미사
- 예: CardProps, HeaderProps
type을 사용하는 경우
- 유니언 타입, 튜플, 리터럴 타입이 꼭 필요한 경우
- 예:
type ButtonVariant = 'primary' | 'secondary'
- 예:
타입 파일 구성
- 컴포넌트와 관련된 타입은 가능한 같은 폴더 내부에 co-locate
- 규모가 커지면 types.ts로 분리
🌎 함수
함수 네이밍(동사 + 명사)
- 함수는 무엇을 하는지가 이름만으로 드러나야 한다
- 의미별 prefix를 통일
get: 값을 가져와 반환(조회)create: 새 값을 생성check: 조건을 검사convert: 형태를 변환add / minus: 더하거나 빼기filter: 필터링 결과를 반환
- boolean 반환 유틸은 is으로 시작
- 예: isEmailValid, isSubmit
함수 선언 방식
- 화살표 함수(arrow function)를 우선 사용해요.
- 컴포넌트 내부/유틸 함수 스타일을 통일하기 위함이에요.
key 사용 규칙
- key에 랜덤 값을 넣지 않는다
- 리스트가 동적이면 반드시 고유 id를 key로 사용
- 정적 리스트(순서/개수 변화 없음)에서는 index 허용
🪢 메소드
배열/객체 처리
- 배열 복사는 스프레드 연산자 사용
- 예: const copy = [...original]
- 반복은 가능하면 map, forEach, filter, reduce를 사용
- 단순 루프라도 “결과물이 무엇인지” 드러나는 메소드 우선
구조 분해 할당
- props/객체는 가능한 구조 분해로 받아서 사용
🎨 스타일
네이밍 규칙
- 특정 요소를 감싸는 래퍼가 필요하다면 container로 통일
- 예: pageContainer, buttonContainer
- 스타일 이름은 반드시 의미를 드러내기
- 예: titleSection, emptyStateContainer, textContainer
CSS 속성 작성 순서
- 가능한 범위에서 바깥 → 안쪽 흐름으로 작성
- display → position → size → spacing → border/background → typography → etc
📓 스토리북
작성 목적
- Storybook은 보여주기뿐 아니라 컴포넌트 사용법 문서화가 목적
- Story에 Props 설명(특히 interface 기반)을 포함
규칙
- title은 폴더 구조를 반영
- 예: Common/Box, Components/Button
- componentSubtitle로 컴포넌트 한 줄 설명
- docs.description.component에 다음 내용 포함
- 컴포넌트 역할
- 핵심 Props 설명
- 동작 조건(예: 특정 prop일 때 버튼 노출 등)
- 대표 케이스를 Story로 분리
- Default, WithButtonLabel, Disabled, ErrorState 등
🧪 테스트 코드
테스트 목표
- 테스트는 깨지면 치명적인 흐름을 보호하는 게 목적
우선순위
- 유틸 함수 / 변환 로직
- 입력 → 출력이 명확해서 테스트 효율이 높다
- 비즈니스 핵심 플로우
- 예: 메모 생성/저장/요약 결과 저장 같은 핵심 기능
- 컴포넌트 테스트
- 상호작용이 중요한 UI (버튼 클릭, 폼 제출, 조건부 렌더링)
규칙
- 테스트 파일은 보통 *.test.ts(x)
- 예: it('submits form when valid', ...)
⭐️ 그라운드 룰
모르는 건 꼭 물어보기
- 고민하지 말고 바로 물어보기
- 질문은 능력 부족이 아니라, 성장 의지
- 디스코드/노션/카톡 어떤 채널이든 편하게 질문하기
지식 공유하기
- 공유 예시
- 이 에러 이렇게 해결했어요 → 노션 정리
- 이 구조가 더 좋더라 → 회의 때 공유
- 이 글 도움 됐어요 → 링크 공유
문서화를 잘 하기
- 구조를 바꿨다면 → 왜 바꿨는지 기록
- 규칙을 정했다면 → README/노션에 남기기
- 트러블슈팅을 했다면 → 해결 과정 정리
우리 팀의 핵심 가치
- 질문하는 용기
- 공유하는 문화
- 문서화하는 습관
- 코딩 이후까지 책임지는 태도
- 리뷰를 존중하는 자세
- 도전을 두려워하지 않는 마음
└── src/
├── app/
│ ├── main.tsx
│ └── App.tsx
├── pages/
│ ├── home/ // 페이지 단위 도메인 폴더
│ │ ├── apis/ // 도메인 관련 API
│ │ ├── components/ // 도메인 관련 컴포넌트
│ │ ├── utils/ // 도메인 관련 유틸 함수
│ │ ├── hooks/ // 도메인 관련 훅
│ │ └── home-page.tsx // 도메인 UI
│ ├── ai-results/
│ ├── login/
│ ├── memo/
│ ├── landing/
│ └── ...
├── router/ // 라우팅 설정
│ ├── path.ts
│ ├── lazy.ts
│ ├── router.ts
│ └── ...
└── shared/ // 공통으로 사용되는 것들을 모아놓은 폴더
├── api/ // 공통 API 설정
│ ├── interceptor/ // Axios 인터셉터
│ ├── instance.ts
│ └── status.ts
├── components/ // 공통 컴포넌트
│ ├── header/
│ ├── sidebar/
│ └── ...
├── configs/ // 앱 전역 설정
├── constants/ // 공통 상수
├── hooks/ // 공통 커스텀 훅
├── utils/ // 공통 유틸 함수
├── libs/ // 공통 라이브러리 래퍼/설정(외부 라이브러리 초기화 등)
└── types/ // 공통 타입 정의
└── packages/ // 모노레포 워크스페이스: 앱과 공통 패키지를 분리해 재사용/버전관리
├── cds-ui/ // Clustar 디자인 시스템
│ └── src/
| ├── components
| ├── styles
| ├── token
│ └── ...
├── cds-icons/ // 아이콘 패키지(React 컴포넌트화된 SVG 등)
├── eslint-config/ // 공통 ESLint 설정 패키지
└── typescript-config/ // 공통 TS config 패키지
└── pnpm-workspace.yaml // 카탈로그 설정 파일
![]() 조혜린 |
![]() 백지연 |
![]() 최윤하 |
![]() 임서준 |







