흩어진 메모를 빛나는 결과물로
![]() 조혜린 |
![]() 백지연 |
![]() 최윤하 |
![]() 임서준 |
브랜치 전략: 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 제목은 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 제목은 작업 성격을 바로 알 수 있도록 prefix 추가
-
[Init] 프로젝트 초기 세팅
-
[Feat] Tab 컴포넌트 구현
-
[Fix] 색상 수정
-
[Refactor] API 모듈 구조 개선
merge 조건
- PR은 최소 2명 이상의 Approve가 있어야 merge 가능
- 직접 push로 합치는 방식은 지양,, 반드시 PR을 통해 merge
리뷰 타임
- PR이 올라오면 가능한 빨리 리뷰해요.
- 몰아서 한 번에가 아니라, 올라오는 즉시 분산 리뷰가 원칙이에요.
리뷰 기준
- 리뷰 코멘트는 최대한 둥글게 작성해요.
- 근거있는 주장으로 이야기해요
- 가능한 경우 레퍼런스(문서/가이드/팀 규칙)를 함께 첨부해요.
리뷰에서 중요하게 보는 포인트 예시
- 아키텍처/폴더 구조 일관성
- 예외 처리/에러 핸들링
- 성능에 영향 줄 수 있는 부분(불필요 렌더링, 무거운 연산 등)
- 타입 안정성(TypeScript), API 계약 준수
- 접근성/UX 고려(로딩/에러 상태 등)
- 네이밍/가독성(우리 팀이 중요하게 보는 기준)
🧩 컴포넌트
-
리액트 컴포넌트만 PascalCase를 사용해요.
- 예: Header, MemoCard, AiSummaryPanel
-
그 외 유틸/함수/변수는 camelCase를 사용해요.
-
컴포넌트는 기본적으로 default export를 사용해요.
-
import 경로가 단순해지고, “이 파일의 대표 컴포넌트”가 명확해져요.
-
단, 모듈 집합(index.ts)에서는 named export로 re-export해요.
-
팀에서 import 스타일을 통일하기 위함이에요.
-
의미 없는 div 남발을 지양하고, 가능한 시맨틱 태그를 사용해요.
- 예: section, header, main, nav, article, aside, footer
-
최상단 래퍼가 의미가 없다면 Fragment(<>...</>)를 사용해요.
-
children이 불필요한 컴포넌트는 Self closing을 사용해요.
- 예:
<EmptyState />
- 예:
-
이벤트 핸들러 함수는 반드시 handle prefix를 사용해요.
- 예: handleSubmit, handleResetClick
-
이벤트 핸들러가 아닌 일반 함수에는 handle을 사용하지 않아요.
- “이 함수는 이벤트 핸들러다”라는 의미를 유지하기 위함이에요.
📂 폴더명
-
폴더명은 kebab-case + 소문자 시작을 사용해요.
- 예: user-profile, memo-list, error-boundary
-
가능한 경우 복수형(s)을 사용해요. - 예: models, libs, styles, configs
⛓️ 타입
-
타입/인터페이스 이름은 PascalCase를 사용해요.
-
기본적으로 type보다 interface를 우선 사용해요.
- 객체 형태 확장(merge/extends)과 협업 시 확장성 때문에 더 유리해요.
- 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에 랜덤 값을 넣지 않아요.
-
리스트가 동적이면 반드시 고유 id를 key로 사용해요
-
정적 리스트(순서/개수 변화 없음)에서는 index도 허용해요.
🪢 메소드
-
배열 복사는 스프레드 연산자를 사용해요.
- 예: const copy = [...original]
-
반복은 가능하면 map, forEach, filter, reduce를 사용해요.
- 단순 루프라도 “결과물이 무엇인지” 드러나는 메소드를 우선해요.
-
props/객체는 가능한 구조 분해로 받아서 사용해요.
- 가독성과 타입 추적이 쉬워져요.
🎨 스타일
-
특정 요소를 감싸는 래퍼가 필요하다면 container로 통일해요.
- 예: pageContainer, buttonContainer
-
스타일 이름은 반드시 의미를 드러내요.
- 예: titleSection, emptyStateContainer, textContainer
-
가능한 범위에서 “바깥 → 안쪽” 흐름으로 작성해요.
- 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', ...)
💪 export 규칙 (named rule)
-
컴포넌트 파일은 default export를 기본으로 해요.
- 예: ui/button.tsx → export default Button
-
외부로 공개하는 진입점은 index.ts에서 named export로 통일해요.
- import가 예측 가능해지고, 모듈 경계를 명확히 할 수 있어요.
⭐️ 그라운드 룰
모르는 건 꼭 물어보기
모르는 걸 숨기는 것보다, 물어보는 게 훨씬 더 팀에 도움이 돼요.
-
고민하지 말고 바로 물어봐요.
-
질문은 능력 부족이 아니라, 성장 의지예요.
-
디스코드/노션/카톡 어떤 채널이든 편하게 질문해요.
-
이미 아는 사람은 최대한 친절하게 설명해줘요.
지식 공유하기
- 공유 예시
-
“이 에러 이렇게 해결했어요” → 노션 정리
-
“이 구조가 더 좋더라” → 회의 때 공유
-
“이 글 도움 됐어요” → 링크 공유
-
문서화를 잘 하기
-
구조를 바꿨다면 → 왜 바꿨는지 기록
-
규칙을 정했다면 → README/노션에 남기기
-
트러블슈팅을 했다면 → 해결 과정 정리
- 우리가 문서화하는 이유
-
나중에 “이거 왜 이렇게 했지?” 안 해도 돼요.
-
새로운 팀원이 들어와도 빠르게 적응할 수 있어요.
-
리뷰어가 맥락을 이해해서 코드리뷰가 쉬워져요.
-
챌린징을 두려워하지 말기
우리는 ‘안전한 선택’보다 ‘성장하는 선택’을 더 가치 있게 봐요.
-
새로운 기술 도입
-
구조 개선
-
성능 최적화
-
리팩터링 제안
물론 근거 없는 주장이나 아무런 근거 없이 기술을 도입하려고 하면 안돼요. 대신 대신 이렇게 하면 이런 장점이 있어요, 이런 단점은 있을 수 있어요처럼 생각 정리해서 제안하면 돼요.
서로 존중하기
우리는 코드보다 사람이 먼저인 팀이에요.
- 말투 둥글게 하기
- 비판이 아니라, 개선을 목표로 말하기
우리 팀의 핵심 가치
-
질문하는 용기
-
공유하는 문화
-
문서화하는 습관
-
코딩 이후까지 책임지는 태도
-
리뷰를 존중하는 자세
-
도전을 두려워하지 않는 마음
FSD 폴더 구조
└── src/
├── app/ // app 레이어: 앱의 엔트리/조립/전역 설정
│ ├── main.tsx
│ └── App.tsx
├── pages/ // pages 레이어: 라우트 단위 화면(진입점)
│ ├── home/ // pages 내부에서도 ui/model/api를 나눠 화면
│ │ ├── ui
│ │ │ └── memo-page.tsx
│ │ └── index.ts
│ ├── ai-results/
│ ├── login/
│ ├── memo/
│ └── landing/
├── widgets/ // widgets 레이어: 여러 페이지에서 재사용되는 큰 UI 블록
│ ├── header/
│ ├── sidebar/
│ │ ├── api/
│ │ ├── ui/
│ │ ├── model/
│ │ └── ...
│ └── ...
├── features/ // features 레이어: 유저 행동/기능 단위(로그인, 메모 생성, 요약 생성 등)
├── entities/ // entities 레이어: 도메인 모델(메모, 사용자, AI결과물 등)
└── shared/ // shared 레이어: 전 레이어에서 쓰는 범용 공통(순수/재사용)
├── api/
│ ├── instance.ts
│ └── configs/ // API 공통 설정(전역)
│ ├── end-point.ts
│ └── status.ts
├── configs/
│ └── app-config.ts
├── libs/ // 공통 라이브러리 래퍼/설정(외부 라이브러리 초기화 등)
│ ├── query-client.ts // TanStack Query QueryClient 설정(전역 공통)
│ └── sentry-init.ts // Sentry init
├── router/ // 라우팅
│ ├── routes/
│ ├── path.ts
│ ├── router.ts
│ └── ...
└── packages/ // 모노레포 워크스페이스: 앱과 공통 패키지를 분리해 재사용/버전관리
├── cds-ui/
│ └── src/
| ├── components
| ├── styles
| ├── token
│ └── ...
├── cds-icons/ // 아이콘 패키지(React 컴포넌트화된 SVG 등)
├── eslint-config/ // 공통 ESLint 설정 패키지
└── typescript-config/ // 공통 TS config 패키지
└── pnpm-workspace.yaml // 카탈로그 설정 파일
![]() 조혜린 |
![]() 백지연 |
![]() 최윤하 |
![]() 임서준 |







