diff --git "a/.github/ISSUE_TEMPLATE/\352\270\260\353\212\245-\354\232\224\354\262\255-feature-request--\355\205\234\355\224\214\353\246\277.md" "b/.github/ISSUE_TEMPLATE/\352\270\260\353\212\245-\354\232\224\354\262\255-feature-request--\355\205\234\355\224\214\353\246\277.md" new file mode 100644 index 00000000..730d5d34 --- /dev/null +++ "b/.github/ISSUE_TEMPLATE/\352\270\260\353\212\245-\354\232\224\354\262\255-feature-request--\355\205\234\355\224\214\353\246\277.md" @@ -0,0 +1,65 @@ +--- +name: 기능 요청(Feature Request) 템플릿 +about: 기능 요청은 자신이 할 일을 큰 범주로 나눌때 써도 되고, 동료에게 작업을 요청할때 쓰면 됩니다. +title: '' +labels: '' +assignees: '' + +--- + +## 📌 요청 기능 설명 + +> 추가하고자 하는 기능이 무엇인지 간단히 설명해주세요. +> 예: "사용자 프로필 페이지에 다크 모드 추가" + +--- + +**설명**: 간단하고 명료하게 추가하려는 기능의 개요를 적습니다. 이 부분은 제목과도 연관성이 있어야 하며, 이슈 리스트에서 다른 팀원들이 쉽게 이슈의 내용을 이해할 수 있도록 작성합니다. + +--- + +## 📝 기능 세부 사항 + +> 기능의 동작 방식과 구체적인 요구사항을 작성해주세요. +> - 예: 사용자가 다크 모드를 켤 수 있는 토글 스위치가 있어야 함 +> - 예: 다크 모드에서 배경색과 텍스트 색상이 변경되어야 함 +> - 예: 사용자가 설정한 다크 모드 상태가 로컬 저장소에 저장되어야 함 + +--- + +**설명**: 기능의 세부사항은 해당 기능이 완성될 때의 모습과 이를 위해 필요한 요소들을 구체적으로 나열합니다. 특히 팀 내에서 동일한 이해를 갖추도록, UI 요소, 상호작용, 데이터 저장 방식 등을 가능한 한 상세히 기술합니다. + +--- + +## 🤔 기능 추가 배경 및 목적 + +> 왜 이 기능이 필요한지 설명해주세요. 기능이 해결할 문제나 개선될 사항에 대해 적어주세요. +> 예: "다크 모드는 사용자들에게 더 나은 시각적 경험을 제공하며, 눈의 피로를 줄여줌" + +--- + +**설명**: 기능 요청의 목적을 서술하여, 이 기능이 사용자의 경험을 어떻게 개선할지, 또는 기존 문제를 어떻게 해결할지 설명합니다. 이를 통해 기능의 우선순위와 필요성을 파악할 수 있습니다. + +--- + +## 🚩 완료 조건 (Acceptance Criteria) + +> 기능이 완료되었음을 판단할 수 있는 조건을 명확히 정의해주세요. +> - [ ] 사용자가 프로필 페이지에서 다크 모드를 선택할 수 있음 +> - [ ] 다크 모드 선택 시 배경색과 텍스트 색상이 적절히 변경됨 +> - [ ] 페이지 새로 고침 시에도 다크 모드 상태가 유지됨 + +--- + +**설명**: 완료 조건은 이 기능이 완성되었음을 판단할 수 있는 명확한 기준입니다. 체크리스트 형식으로 작성하여 팀원들이 각각의 조건을 충족하는지 쉽게 확인할 수 있게 합니다. + +--- + +## 💡 참고 자료 (선택) + +> 관련된 레퍼런스나 문서 링크, UI 디자인 시안, 기타 참고할 수 있는 자료를 첨부해주세요. +> 예: "디자인 시안 URL", "참고할 라이브러리 링크", "기존 다크 모드 구현 사례 링크" + +--- + +**설명**: 필요한 참고 자료가 있다면 링크나 설명을 추가하여 기능 구현 시 활용할 수 있도록 합니다. 이로써, 개발자는 더 나은 구현 방향을 잡고, 디자이너와 협업할 때 필요한 정보를 쉽게 얻을 수 있습니다. diff --git "a/.github/ISSUE_TEMPLATE/\353\254\270\354\204\234\355\231\224-documentation--\355\205\234\355\224\214\353\246\277.md" "b/.github/ISSUE_TEMPLATE/\353\254\270\354\204\234\355\231\224-documentation--\355\205\234\355\224\214\353\246\277.md" new file mode 100644 index 00000000..a305a46c --- /dev/null +++ "b/.github/ISSUE_TEMPLATE/\353\254\270\354\204\234\355\231\224-documentation--\355\205\234\355\224\214\353\246\277.md" @@ -0,0 +1,64 @@ +--- +name: 문서화(Documentation) 템플릿 +about: 문서화 작성에 앞서서 양식이나 작성 시나리오 등을 서술하는 이슈 템플릿입니다. +title: '' +labels: '' +assignees: '' + +--- + +## 📄 문서화 항목 + +> 작성할 문서의 이름이나 주제를 간단히 적어주세요. +> 예: "API 명세 작성", "프로젝트 설치 가이드 작성" + +--- + +**설명**: 작성할 문서의 제목이나 주제를 간단히 요약하여 문서화의 목적을 한눈에 파악할 수 있도록 합니다. 이슈 목록에서 문서화 작업을 쉽게 찾을 수 있게 합니다. + +--- + +## 📝 문서 내용 요약 + +> 문서에 포함될 내용의 개요를 간단히 설명해주세요. +> 예: "API 엔드포인트 목록 및 응답 형식을 설명" + +--- + +**설명**: 문서의 핵심 내용을 요약하여 작업의 방향성을 명확히 합니다. 이 항목은 문서가 다루는 주요 내용을 팀원들에게 소개하고, 작업의 큰 그림을 제공하는 역할을 합니다. + +--- + +## 📚 문서 내용 세부 사항 + +> 문서에 포함될 구체적인 항목을 나열해주세요. +> - [ ] 사용자 인증 API의 엔드포인트 설명 +> - [ ] 응답 데이터 예시 +> - [ ] 필수 및 선택 매개변수 설명 +> - [ ] 응답 코드 및 에러 처리 방식 설명 + +--- + +**설명**: 문서의 세부 항목을 나열하여 필요한 세부 내용을 명확히 정의합니다. 이를 통해 문서 작성자가 각 항목을 빠짐없이 작성할 수 있으며, 다른 팀원들도 문서에서 원하는 정보를 쉽게 찾을 수 있습니다. + +--- + +## 🛠️ 작성 가이드라인 (선택) + +> 문서 작성 시 필요한 규칙이나 참고 사항을 추가해주세요. +> 예: "REST API 명명 규칙에 따라 작성", "데이터 타입 표기를 명확히 할 것" + +--- + +**설명**: 문서화 시 적용할 가이드라인을 설정하여 일관된 문서 스타일을 유지합니다. API 명세의 경우 특정 명명 규칙을 따르거나, 데이터 타입 표기를 명확히 하는 등의 규칙을 제시하면 다른 팀원들이 쉽게 이해할 수 있는 문서가 됩니다. + +--- + +## 🔗 참고 자료 (선택) + +> 필요한 경우 외부 레퍼런스 링크나 내부 자료 링크를 첨부해주세요. +> 예: "REST API 표준 문서 링크", "프로젝트 관련 기술 문서 링크" + +--- + +**설명**: 문서화 작업 시 참고할 자료가 있다면, 링크나 파일 경로를 제공하여 작업자가 쉽게 접근할 수 있게 합니다. 외부 표준 문서, 기술 문서 링크는 정확한 정보를 제공하는 데 유용합니다. diff --git "a/.github/ISSUE_TEMPLATE/\353\262\204\352\267\270-\353\263\264\352\263\240-bug-report--\355\205\234\355\224\214\353\246\277.md" "b/.github/ISSUE_TEMPLATE/\353\262\204\352\267\270-\353\263\264\352\263\240-bug-report--\355\205\234\355\224\214\353\246\277.md" new file mode 100644 index 00000000..1b145708 --- /dev/null +++ "b/.github/ISSUE_TEMPLATE/\353\262\204\352\267\270-\353\263\264\352\263\240-bug-report--\355\205\234\355\224\214\353\246\277.md" @@ -0,0 +1,91 @@ +--- +name: 버그 보고(Bug Report) 템플릿 +about: 버그 발생 시 알리는 템플릿입니다. 보통 바로 수정할 게 아니기에, 재현가능하게 적어야 합니다. +title: '' +labels: '' +assignees: '' + +--- + +## 🐞 버그 설명 + +> 버그가 무엇인지 간단히 요약해주세요. +> 예: "로그인 버튼이 클릭되지 않음" + +--- + +**설명**: 이 항목에서는 버그를 간단하게 요약합니다. 이슈 목록에서 다른 팀원들이 빠르게 버그의 개요를 이해할 수 있도록 짧고 명료하게 작성합니다. 특히, "어떤 상황에서 어떤 문제가 발생하는지"를 빠르게 파악할 수 있도록 합니다. + +--- + +## 📋 테스트 환경 + +> 버그가 발생한 환경에 대해 작성해주세요. +> - OS / 브라우저: (예: Windows 10 / Chrome 94) +> - 프레임워크 버전: (예: React 17, Node.js 14) +> - 기타: (예: 모바일/데스크탑 모드, 네트워크 속도 등) + +--- + +**설명**: 버그가 특정 환경에서만 발생할 수 있으므로, 개발 및 테스트 환경을 명확히 기재하여 문제 재현성을 높입니다. OS, 브라우저, 프레임워크 버전 등의 정보는 같은 환경에서 테스트하고 문제를 확인하는 데 매우 중요합니다. + +--- + +## 📝 버그 상황 설명 + +> **Given-When-Then** 형식으로 서술해주세요. +> - Given: 사용자가 로그인 페이지에 접속했을 때 +> - When: 로그인 버튼을 클릭하면 +> - Then: 에러 메시지가 나타나지 않고 페이지가 멈추어야 함 +> 문제 상황 재현을 위해 스크린샷이나 동영상을 첨부해주세요 (선택) + +--- + +**설명**: 버그 상황을 Given-When-Then 형식으로 작성하면 문제가 발생한 상황과 그 조건을 더욱 명확하게 설명할 수 있습니다. 이는 특히 QA팀이나 다른 개발자들이 동일한 문제를 재현하는 데 매우 유용합니다. 스크린샷이나 동영상은 문제를 이해하는 데 큰 도움이 됩니다. + +--- + +## 🚩 재현 방법 + +> 문제 상황을 재현하기 위해 필요한 단계들을 상세하게 작성해주세요. +> 1. 로그인 페이지에 접속합니다. +> 2. 올바른 아이디와 비밀번호를 입력합니다. +> 3. 로그인 버튼을 클릭합니다. +> 4. 에러 메시지가 표시됩니다. + +--- + +**설명**: 재현 방법은 버그를 다시 확인할 수 있도록 단계별로 구체적으로 작성합니다. 이를 통해 다른 개발자가 재현 방법만 따라하면 동일한 상황을 쉽게 재현할 수 있습니다. + +--- + +## ✅ 기대 결과 + +> 예상했던 정상적인 결과가 어떤 것이었는지 설명해주세요. +> 예: "로그인 버튼 클릭 시 홈 페이지로 리디렉션되어야 함" + +--- + +**설명**: 기대 결과는 문제 상황에서 의도했던 정상적인 동작을 명확히 설명하는 부분입니다. 이를 통해 실제 결과와 비교하여 어떤 점이 정상적이지 않은지 쉽게 파악할 수 있습니다. + +--- + +## 🔍 실제 결과 + +> 발생한 실제 결과가 무엇인지 설명해주세요. +> 예: "로그인 버튼을 클릭해도 아무 반응이 없고, 페이지가 고정됨" + +--- + +**설명**: 실제 결과는 발생한 문제의 구체적인 증상을 설명하는 부분입니다. 기대 결과와의 차이를 명확히 설명하면, 문제 해결에 더욱 도움이 됩니다. + +--- + +## 💡 참고 자료 (선택) + +> 문제와 관련해서 참고할만한 자료를 적어주세요. +> 예: 로그 파일, 오류 메시지, 관련된 이슈 링크 + +--- + +**설명**: 추가적인 로그 파일이나 관련 이슈 링크가 있다면, 여기에 작성하여 문제 해결에 필요한 정보를 더 많이 제공할 수 있습니다. 이 정보는 개발자가 문제의 원인을 더욱 쉽게 파악할 수 있도록 도와줍니다. diff --git "a/.github/ISSUE_TEMPLATE/\354\236\221\354\227\205-task--\355\205\234\355\224\214\353\246\277.md" "b/.github/ISSUE_TEMPLATE/\354\236\221\354\227\205-task--\355\205\234\355\224\214\353\246\277.md" new file mode 100644 index 00000000..7ffabea7 --- /dev/null +++ "b/.github/ISSUE_TEMPLATE/\354\236\221\354\227\205-task--\355\205\234\355\224\214\353\246\277.md" @@ -0,0 +1,78 @@ +--- +name: 작업(Task) 템플릿 +about: '기능 요청사항에 대한 세분화한, 실제 개발 단위인 Task에 관한 문서입니다. ' +title: '' +labels: '' +assignees: '' + +--- + +## 📌 작업 제목 + +> 작업의 이름을 간단히 적어주세요. +> 예: "헤더 컴포넌트 구현" + +--- + +**설명**: 작업의 제목은 간결하고 직관적으로 작성하여 이슈 목록에서 쉽게 파악할 수 있도록 합니다. 특정 기능 개발, 디자인 조정, 코드 리팩토링 등 다양한 작업에 적용될 수 있습니다. + +--- + +## 🎯 목표 + +> 이 작업의 목표나 목적을 설명해주세요. +> 예: "헤더 컴포넌트를 구현하여 모든 페이지에 통일된 네비게이션을 제공" + +--- + +**설명**: 작업의 목표는 이 작업이 프로젝트에서 수행하는 역할과 그 필요성을 설명합니다. 이를 통해 팀원들이 작업의 중요도와 필요성을 이해할 수 있습니다. + +--- + +## 📝 작업 세부 사항 + +> 작업에 대한 구체적인 내용을 작성합니다. +> - 컴포넌트 구조 +> - UI 스타일 +> - 데이터 흐름 +> - 예: 헤더 컴포넌트는 로고, 네비게이션 메뉴, 검색창으로 구성되어야 함 + +--- + +**설명**: 작업의 세부 사항은 필요한 요소와 구현 방식에 대해 명확히 서술하여 작업의 완성도를 높입니다. UI 요소, 데이터 흐름, API 요청 등의 구체적인 요구사항을 나열하여 팀원들이 작업을 진행할 때 참고할 수 있도록 합니다. + +--- + +## 🚩 완료 조건 (Acceptance Criteria) + +> 작업 완료를 판단할 수 있는 기준을 명확히 작성해주세요. +> - [ ] 헤더 컴포넌트가 페이지 상단에 고정됨 +> - [ ] 모바일 및 데스크탑에서 반응형 동작이 잘 작동함 +> - [ ] 네비게이션 메뉴가 모든 페이지에서 일관되게 동작함 + +--- + +**설명**: 완료 조건은 작업이 완성되었음을 확인할 수 있는 체크리스트 형태로 작성하여 작업의 명확한 종료 시점을 제공합니다. 이를 통해 QA 및 다른 팀원들이 작업 완료 여부를 쉽게 확인할 수 있습니다. + +--- + +## 📅 예상 소요 시간 및 일정 + +> 예상 소요 시간을 작성해주세요 (예: 2일, 5시간 등) +> 작업을 시작 및 완료할 예상 일정을 간단히 작성하면 더욱 좋습니다. +> 예: "이 작업은 2일이 소요될 예정이며, 이번 주 내로 완료 예정" + +--- + +**설명**: 예상 소요 시간과 일정을 작성하여 작업의 우선순위와 마일스톤을 설정하는 데 도움이 됩니다. 또한, 작업의 진행 상황을 추적할 수 있어 프로젝트 일정 관리에 유용합니다. + +--- + +## 💡 참고 자료 (선택) + +> 필요한 경우 외부 레퍼런스 링크나 내부 자료 링크를 첨부해주세요. +> 예: "헤더 디자인 시안 URL", "참고할 UI 라이브러리 링크" + +--- + +**설명**: 작업에 필요한 참고 자료가 있다면, 여기에 첨부하여 개발자가 작업을 진행할 때 필요한 자료를 손쉽게 찾아볼 수 있게 합니다. 디자인 시안, 유사한 UI/UX 구현 링크, 외부 라이브러리 참고 자료 등이 유용할 수 있습니다. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..fbcd3483 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,87 @@ +--- +name: PR 템플릿 +about: PR 날릴 때 사용하시면 됩니다. +title: '' +labels: '' +assignees: '' + +--- + +## 📝 PR 개요 + +> 이 PR에서 어떤 변경이 이루어졌는지 간략히 설명해주세요. +> 예: "로그인 페이지 UI 개선 및 다크 모드 추가" + +--- + +## 🔍 변경 사항 + +> PR에서 변경된 주요 내용을 구체적으로 설명해주세요. +> - 로그인 페이지의 레이아웃을 수정하여 사용자 경험 개선 +> - 다크 모드 기능 추가 및 상태 관리 로직 구현 +> - 테스트 코드 추가로 다크 모드 기능 검증 + +--- + +**설명**: 이 항목에서는 코드의 주요 변경 사항을 나열하여 리뷰어가 코드 수정의 목적을 쉽게 파악할 수 있도록 합니다. 변경된 주요 로직이나 UI 수정 사항이 있다면 구체적으로 설명합니다. + +--- + +## ✅ 체크리스트 (Checklist) + +- [ ] 코드가 빌드 오류 없이 잘 작동하는지 확인 +- [ ] 테스트가 통과하는지 확인 +- [ ] 스타일 가이드와 일관성을 유지했는지 확인 +- [ ] 관련 문서가 업데이트되었는지 확인 (선택 사항) +- [ ] 리뷰어가 이해할 수 있도록 주석이나 설명을 추가했는지 확인 + +--- + +**설명**: 이 체크리스트는 PR 작성자가 스스로 점검할 수 있는 기준을 제시합니다. 코드가 빌드 오류 없이 작동하고, 테스트를 통과하며, 스타일 가이드를 따르고 있는지 확인하는 항목들입니다. + +--- + +## 🔄 관련 이슈 (Linked Issues) + +> 이 PR과 관련된 이슈 번호를 적어주세요. (예: #123) +> 예: "다크 모드 기능 요청 이슈(#45) 해결" + +--- + +**설명**: 이 PR과 관련된 이슈 번호를 링크하여 리뷰어가 관련된 문제나 요청 사항을 쉽게 참고할 수 있도록 합니다. 이를 통해 이슈와 PR을 연결하여 작업의 목적을 명확히 할 수 있습니다. + +--- + +## 📷 스크린샷 및 동영상 (선택 사항) + +> UI 변경 사항이 있는 경우 스크린샷이나 동영상을 첨부해주세요. +> 예: 변경된 로그인 페이지 화면 캡처 + +--- + +**설명**: UI 변경 사항이 포함된 경우, 변경된 화면을 시각적으로 보여주기 위해 스크린샷이나 동영상을 첨부하면 도움이 됩니다. 리뷰어는 화면 변경 사항을 바로 확인할 수 있어 코드 리뷰가 더 효과적입니다. + +--- + +## 🧪 테스트 방법 + +> 변경 사항을 검토할 때 어떻게 테스트해야 하는지 단계별로 설명해주세요. +> 예: +> 1. 로그인 페이지로 이동합니다. +> 2. 다크 모드 스위치를 클릭합니다. +> 3. 배경색이 다크 모드로 변경되는지 확인합니다. + +--- + +**설명**: 코드 변경 사항을 검토할 때 사용할 테스트 방법을 구체적으로 설명하여, 리뷰어가 쉽게 테스트를 수행할 수 있도록 합니다. 특정 기능이나 UI 요소에 대한 테스트 방법을 안내하면 코드 리뷰 속도가 빨라집니다. + +--- + +## 📚 참고 자료 (선택 사항) + +> PR과 관련된 참고 자료가 있다면 링크나 설명을 첨부해주세요. +> 예: "다크 모드 구현을 위한 라이브러리 사용 가이드 링크" + +--- + +**설명**: 참고할 자료가 있다면 여기에 적어 리뷰어가 필요한 경우 해당 자료를 참조할 수 있게 합니다. 외부 라이브러리나 참고할 문서, API 명세 링크 등이 포함될 수 있습니다. diff --git a/.github/workflows/auto-assign-reviewers.yml b/.github/workflows/auto-assign-reviewers.yml index df1055ba..ba48e125 100644 --- a/.github/workflows/auto-assign-reviewers.yml +++ b/.github/workflows/auto-assign-reviewers.yml @@ -1,24 +1,54 @@ -# PR 이벤트 발생 시(opened), 라벨이 붙는 이벤트 발생 시(labeled) 자동으로 팀원 중 Reviewer 2명 지정 name: 'Auto Assign Reviewers' on: pull_request: - types: [ opened, labeled ] + types: [opened, labeled] jobs: assign_reviewers: runs-on: ubuntu-latest steps: - - name: 'Check for label' + - name: 'Set Assignee to Author' uses: actions/github-script@v6 - id: label_check with: script: | - const labels = context.payload.pull_request.labels; - return labels.some(label => label.name === '확인 요청'); + if (context.payload.pull_request) { + await github.rest.issues.addAssignees({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + assignees: [context.payload.pull_request.user.login], + }); + } else { + console.log('No pull_request data found in context.payload'); + } + + - name: 'Add "확인 요청" Label if not present' + uses: actions/github-script@v6 + with: + script: | + const labels = context.payload.pull_request.labels || []; + if (!labels.some(label => label.name === '확인 요청')) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + labels: ['확인 요청'], + }); + } + + - name: 'Determine Number of Reviewers' + id: determine_reviewers + uses: actions/github-script@v6 + with: + script: | + const targetBranch = context.payload.pull_request.base.ref; + const reviewers = targetBranch === 'main' ? 3 : 2; + core.setOutput('number_of_reviewers', reviewers); + - name: 'Assign Reviewers' - if: steps.label_check.outputs.result == 'true' uses: kentaro-m/auto-assign-action@v2.0.0 with: repo-token: '${{ secrets.GITHUB_TOKEN }}' - configuration-path: '.github/auto_assign_config.yml' # 이부분은 차후 생성하겠습니다 + configuration-path: '.github/auto_assign_config.yml' + numberOfReviewers: ${{ steps.determine_reviewers.outputs.number_of_reviewers }} diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index bc2a53b2..3a7ec38c 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -1,4 +1,3 @@ -# Reviewer 2명이 리뷰를 남기고 승인한 뒤, 라벨이 "작업 완료"로 변경되고 자동으로 특정 브랜치에 Merge하기 name: 'Auto Merge Approved PRs' on: @@ -21,6 +20,7 @@ jobs: pull_number: context.payload.pull_request.number, }); return JSON.stringify(pr); + - name: 'Check Approvals and Labels' id: check uses: actions/github-script@v6 @@ -34,19 +34,25 @@ jobs: }); const approvals = reviews.data.filter(review => review.state === 'APPROVED'); const hasLabel = pr.labels.some(label => label.name === '확인 요청'); - return approvals.length >= 2 && hasLabel; + + // 메인 브랜치로 향하는 PR인 경우 리뷰어 3명, 다른 브랜치인 경우 2명 필요 + const requiredApprovals = pr.base.ref === 'main' ? 3 : 2; + return approvals.length >= requiredApprovals && hasLabel; + - name: 'Change Label to 작업 완료' if: steps.check.outputs.result == 'true' uses: actions-ecosystem/action-add-labels@v1 with: labels: '작업 완료' github_token: ${{ secrets.GITHUB_TOKEN }} + - name: 'Remove Label 확인 요청' if: steps.check.outputs.result == 'true' uses: actions-ecosystem/action-remove-labels@v1 with: labels: '확인 요청' github_token: ${{ secrets.GITHUB_TOKEN }} + - name: 'Merge PR' if: steps.check.outputs.result == 'true' uses: actions/github-script@v6 @@ -56,4 +62,6 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, pull_number: context.payload.pull_request.number, + merge_method: 'merge', # 'squash' 또는 'rebase'로도 설정 가능 + commit_title: `자동 머지: PR #${context.payload.pull_request.number}` }); diff --git a/.gitignore b/.gitignore index d3ed148d..3cb8b849 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,8 @@ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 -#husky -.husky +#TMP +tmp #DOCS /docs diff --git a/.husky/_/.gitignore b/.husky/_/.gitignore new file mode 100644 index 00000000..f59ec20a --- /dev/null +++ b/.husky/_/.gitignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/.husky/_/applypatch-msg b/.husky/_/applypatch-msg new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/applypatch-msg @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/commit-msg b/.husky/_/commit-msg new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/commit-msg @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/h b/.husky/_/h new file mode 100644 index 00000000..bf7c8964 --- /dev/null +++ b/.husky/_/h @@ -0,0 +1,22 @@ +#!/usr/bin/env sh +[ "$HUSKY" = "2" ] && set -x +n=$(basename "$0") +s=$(dirname "$(dirname "$0")")/$n + +[ ! -f "$s" ] && exit 0 + +if [ -f "$HOME/.huskyrc" ]; then + echo "husky - '~/.huskyrc' is DEPRECATED, please move your code to ~/.config/husky/init.sh" +fi +i="${XDG_CONFIG_HOME:-$HOME/.config}/husky/init.sh" +[ -f "$i" ] && . "$i" + +[ "${HUSKY-}" = "0" ] && exit 0 + +export PATH="node_modules/.bin:$PATH" +sh -e "$s" "$@" +c=$? + +[ $c != 0 ] && echo "husky - $n script failed (code $c)" +[ $c = 127 ] && echo "husky - command not found in PATH=$PATH" +exit $c diff --git a/.husky/_/husky.sh b/.husky/_/husky.sh new file mode 100644 index 00000000..f9d06379 --- /dev/null +++ b/.husky/_/husky.sh @@ -0,0 +1,9 @@ +echo "husky - DEPRECATED + +Please remove the following two lines from $0: + +#!/usr/bin/env sh +. \"\$(dirname -- \"\$0\")/_/husky.sh\" + +They WILL FAIL in v10.0.0 +" \ No newline at end of file diff --git a/.husky/_/post-applypatch b/.husky/_/post-applypatch new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/post-applypatch @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/post-checkout b/.husky/_/post-checkout new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/post-checkout @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/post-commit b/.husky/_/post-commit new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/post-commit @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/post-merge b/.husky/_/post-merge new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/post-merge @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/post-rewrite b/.husky/_/post-rewrite new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/post-rewrite @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/pre-applypatch b/.husky/_/pre-applypatch new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/pre-applypatch @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/pre-auto-gc b/.husky/_/pre-auto-gc new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/pre-auto-gc @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/pre-commit b/.husky/_/pre-commit new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/pre-commit @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/pre-merge-commit b/.husky/_/pre-merge-commit new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/pre-merge-commit @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/pre-push b/.husky/_/pre-push new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/pre-push @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/pre-rebase b/.husky/_/pre-rebase new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/pre-rebase @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/_/prepare-commit-msg b/.husky/_/prepare-commit-msg new file mode 100755 index 00000000..16aae78f --- /dev/null +++ b/.husky/_/prepare-commit-msg @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/h" \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..34f2fb24 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,17 @@ +echo "🔍 commit 이전에 lint 규칙을 적용합니다..." +if pnpm lint-staged; then + echo "✅ 모든 lint 규칙이 성공적으로 적용되었습니다." + exit 0 +else + echo "❌ lint 규칙 검사에서 오류가 발생했습니다." + exit 1 +fi + +echo "🔍 commit 이전에 test를 실행합니다..." +if pnpm test; then + echo "✅ 모든 Test를 통과하셨습니다." + exit 0 +else + echo "❌ Test를 통과하지 못했습니다." + exit 1 +fi \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 7927b540..1b3cc2f9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -10,7 +10,7 @@ "description": "따라따라의 선따라길따라 BackEnd 코드", "main": "index.js", "scripts": { - "dev": "pnpm src/index.js", + "dev": "node src/index.js", "test": "vitest", "test:watch": "vitest --watch", "test:coverage": "vitest run --coverage", @@ -20,7 +20,9 @@ "author": "", "license": "ISC", "dependencies": { + "dotenv": "^16.4.5", "express": "^4.21.1", + "pg": "^8.13.1", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.1" } diff --git a/backend/src/db.js b/backend/src/db.js new file mode 100644 index 00000000..e19c9d64 --- /dev/null +++ b/backend/src/db.js @@ -0,0 +1,19 @@ +import dotenv from 'dotenv'; +import pg from 'pg'; + +dotenv.config(); + +const { Pool } = pg; + +export const pool = new Pool({ + host: process.env.DB_HOST, + port: process.env.DB_PORT, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, +}); + +pool + .connect() + .then(() => console.log('PostgreSQL 데이터베이스에 연결되었습니다!')) + .catch(err => console.error('데이터베이스 연결 오류:', err)); diff --git a/backend/src/index.js b/backend/src/index.js index e5393134..da1ee137 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,13 +1,26 @@ import express from 'express'; import swaggerUi from 'swagger-ui-express'; -import specs from '../swaggerConfig.js'; +import { specs } from '../swaggerConfig'; +import { pool } from './db'; const app = express(); +app.use(express.json()); const port = 3001; app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs)); -// 예제 라우터 (추가 예정인 라우터의 주석을 Swagger 주석 형식으로 문서화) +// TODO: 데이터베이스에서 데이터 가져오기 예시 +app.get('/guests', async (req, res) => { + try { + const result = await pool.query('SELECT * FROM guest'); + res.json(result.rows); + } catch (err) { + console.error(err); + res.status(500).send('서버 오류'); + } +}); + +// TODO: 예제 라우터 (추가 예정인 라우터의 주석을 Swagger 주석 형식으로 문서화) app.get('/example', (req, res) => { res.send('Hello World'); }); diff --git a/backend/swaggerConfig.js b/backend/swaggerConfig.js index b5861345..09ae4746 100644 --- a/backend/swaggerConfig.js +++ b/backend/swaggerConfig.js @@ -19,6 +19,4 @@ const options = { apis: ['./routes/*.js'], }; -const specs = swaggerJSDoc(options); - -export default specs; +export const specs = swaggerJSDoc(options); diff --git a/frontend/package.json b/frontend/package.json index 0231444f..e948952e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,6 +37,7 @@ "@types/react-dom": "^18.3.1", "@vitejs/plugin-react-swc": "^3.5.0", "autoprefixer": "^10.4.20", + "classnames": "^2.5.1", "eslint": "^9.13.0", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.14", diff --git a/frontend/src/assets/react.svg b/frontend/src/assets/react.svg deleted file mode 100644 index 6c87de9b..00000000 --- a/frontend/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 046d90ed..ae32faeb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -105,9 +105,15 @@ importers: backend: dependencies: + dotenv: + specifier: ^16.4.5 + version: 16.4.5 express: specifier: ^4.21.1 version: 4.21.1 + pg: + specifier: ^8.13.1 + version: 8.13.1 swagger-jsdoc: specifier: ^6.2.8 version: 6.2.8(openapi-types@12.1.3) @@ -166,6 +172,9 @@ importers: autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.47) + classnames: + specifier: ^2.5.1 + version: 2.5.1 eslint: specifier: ^9.13.0 version: 9.14.0(jiti@1.21.6) @@ -1353,6 +1362,9 @@ packages: '@chromatic-com/playwright': optional: true + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -1523,6 +1535,10 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2611,6 +2627,40 @@ packages: resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} engines: {node: '>= 14.16'} + pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + + pg-connection-string@2.7.0: + resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.7.0: + resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.7.0: + resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.13.1: + resolution: {integrity: sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2684,6 +2734,22 @@ packages: resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -2924,6 +2990,10 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -3377,6 +3447,10 @@ packages: xmlcreate@2.0.4: resolution: {integrity: sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -4628,6 +4702,8 @@ snapshots: chromatic@11.16.5: {} + classnames@2.5.1: {} + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -4760,6 +4836,8 @@ snapshots: dom-accessibility-api@0.6.3: {} + dotenv@16.4.5: {} + eastasianwidth@0.2.0: {} ee-first@1.1.1: {} @@ -6012,6 +6090,41 @@ snapshots: pathval@2.0.0: {} + pg-cloudflare@1.1.1: + optional: true + + pg-connection-string@2.7.0: {} + + pg-int8@1.0.1: {} + + pg-pool@3.7.0(pg@8.13.1): + dependencies: + pg: 8.13.1 + + pg-protocol@1.7.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.13.1: + dependencies: + pg-connection-string: 2.7.0 + pg-pool: 3.7.0(pg@8.13.1) + pg-protocol: 1.7.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -6067,6 +6180,16 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postgres-array@2.0.0: {} + + postgres-bytea@1.0.0: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -6366,6 +6489,8 @@ snapshots: space-separated-tokens@2.0.2: {} + split2@4.2.0: {} + stackback@0.0.2: {} statuses@2.0.1: {} @@ -6889,6 +7014,8 @@ snapshots: xmlcreate@2.0.4: {} + xtend@4.0.2: {} + yallist@3.1.1: {} yaml@2.0.0-1: {}