AcaMate_Web/Documents/Project RULE 10.md
2025-04-18 16:46:34 +09:00

227 lines
12 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Coding RULE 10
## 목차
[1⃣ 프로젝트 구조](#1-프로젝트-구조)
[2⃣ 코드 스타일 가이드](#2-코드-스타일-가이드)
[3⃣ Git 규칙](#3-git-규칙)
[4⃣ 작업 프로세스](#4-작업-프로세스)
[5⃣ 협업 및 커뮤니케이션](#5-협업-및-커뮤니케이션)
[6⃣ 테스트 및 품질 관리](#6-테스트-및-품질-관리)
[7⃣ 보안 및 인증 관련](#7-보안-및-인증-관련)
[8⃣ 배포 및 운영](#8-배포-및-운영)
[9⃣ 공통 코드 및 재사용 정책](#9-공통-코드-및-재사용-정책)
[🔟 예외 처리 및 로깅](#10-예외-처리-및-로깅)
---
## 1⃣ 프로젝트 구조
### 🔹 MVVM 구조
#### Model
- 데이터를 정의하는 역할
- ./Program/Models 에 위치
- 별도의 DTO 와 엔티티의 클래스로 구성
#### View
- UI를 정의하는 역할
- ./Program/Views 에 .razor 파일로 선언
- .razor.css 파일로 스타일을 정의
- .razor.cs 파일은 View와 ViewModel을 연결하는 역할만 진행
- 필요시 하위 디렉토리를 만들어 기능별로 묶어서 사용 할 수 있음
#### ViewModel
- UI와 데이터를 연결하는 역할
- ./Program/ViewModels 에 .cs 파일로 선언
- VM.cs 파일은 연결하려는 view.razor 의 view와 같은 이름으로 선언해야 함
- ViewModel은 View와 Model을 연결만 하는 것이 아닌 실제적인 역할을 수행
- ViewModel의 연결 없이 View에서 직접 Model을 사용하여 데이터를 가져올 수 없음
- View에 여러개의 ViewModel이 연결될 수 있음
- 가능한 ViewModel과 View를 1:1로 연결하는 것을 권장
- 테스트를 고려해 ViewModel은 UI 코드에 의존하지 않도록 작성
### 🔹 네임스페이스 구조
- 폴더 구조와 네임스페이스는 반드시 일치해야 함
```csharp
/Program/Pages/Login.razor
namespace Front.Program.Pages;
```
### 🔹 DI
- ViewModel 과 Service는 DI를 통해 주입받아 사용하며 Program.cs 에서 DI를 등록
- ViewModel은 가급적으로 transient로 등록
- 하지만 한 View에서 여러 컴포넌트가 하나의 상태를 공유해야 할 경우에는 Scoped로 등록
- Service는 Scoped으로 등록
- Service는 ViewModel과 다르게 여러 컴포넌트에서 같은 Service를 사용해야 하는 경우가 많기 때문에 Scoped으로 등록
---
## 2⃣ 코드 스타일 가이드
- [C# 코드 스타일 권장 사항 (Microsoft Docs)]("https://learn.microsoft.com/ko-kr/dotnet/csharp/fundamentals/coding-style/coding-conventions")을 따른다.
- 클래스, 인터페이스, 메서드, 변수, 상수 등 모든 명명 및 스타일은 위 문서를 기준으로 작성한다.
- **필요**시 `.editorconfig` 파일을 통해 프로젝트 전체에 스타일 자동 적용 도구를 사용할 수 있다.
---
## 3⃣ Git 규칙
### 🔹 Git Repository
- 실제 팀 Git의 저장소를 사용하여 관리하는 것이 아닌 해당 저장소를 Fork 하여 사용한다.
- Fork한 저장소는 개인의 Gitea 계정에 저장된다.
- 모든 작업은 Fork한 개인저장소에서 진행한다.
- 개인 최종 작업이 끝난 후에 팀 저장소에 Pull Request를 요청한다.
- 이때 PR 작업의 브랜치는 아래 브랜치 규칙에 따라 선택한다.
- PR 작업의 규칙은 아래 PR 규칙을 따른다.
- PR시 반드시 리뷰어의 요청을 통해 머지를 진행한다.
### 🔹 브랜치 규칙
| branch | Description | e.g. |
|:---------:|:-------------:|:-----------------:|
| main | 실제 운영되는 최종 코드 | 배포 전 최종 QA 후 머지 |
| dev | 개발 통합 브랜치 | 모든 feature 브랜치 PR |
| feature/* | 신기능 개발 브랜치 | feature/login |
| bugfix/* | 버그 수정 브랜치 | bugfix/login |
|hotfix/* | 긴급 수정 브랜치 | hotfix/login |
|refactor/*| 리팩토링 브랜치 | refactor/login |
- feature 브랜치는 기능 단위로 나누어 작업하며, 기능이 완료되면 dev 브랜치에 PR을 요청한다.
- dev 브랜치는 모든 feature 브랜치의 통합 브랜치로, QA 후 main 브랜치에 머지된다.
- feature와 bugfix 브랜치는 dev 브랜치를 기준으로 생성한다.
- hotfix 브랜치는 main 브랜치를 기준으로 생성한다.
- refactor 브랜치는 리팩토링 작업을 위한 브랜치로, 기능 추가나 버그 수정과는 별도로 관리한다.
- 브랜치 이름은 소문자로 작성하며, 단어는 '-'로 구분한다.
- 브랜치 이름은 기능이나 버그 수정의 내용을 간결하게 나타내고 최대 3~4단어로 구성하며, 의미가 명확해야 한다.
### 🔹 커밋 메시지 규칙
| Type | Name | Description |
|:----:|:--------:|:--------------------------------------|
| [📝] | Document | 문서 추가, 문서 수정 등 |
| [✨] | feature | 새로운 기능의 추가 |
| [🔥] | fire | 코드나 문서 등의 삭제 |
| [🐛] | bug fix | 버그 수정 |
| [🎨] |STYLE| 코드 포맷팅, 주석, 공백 등 (기능 변경 없음) |
| [♻️] | REFACTOR | 코드 리팩토링 |
| [✅] | TEST | 테스트 코드 추가 |
| [📁] | CHORE| 빌드 업무, 패키지 매니저 수정 등 (.gitignore 수정 등) |
- 커밋 메시지의 작성은 "[imoge] Title - Description" 형식으로 작성한다.
- e.g. "[✨] 로그인 기능 추가 - 로그인 기능을 추가했습니다."
- Title은 10자 이내로 작성하며, 언어의 제약 없이 작성한다.
- Title은 간결하고 명확하게 작성한다.
- Description은 50자 이내로 작성하며, 언어의 제약 없이 작성한다.
- Description은 Title을 보완하는 내용을 작성한다.
- Description은 선택 사항으로, 필요에 따라 작성한다.
### 🔹 PR(Pull Request) 규칙
- PR 제목은 커밋 규칙을 따르되 이슈를 수행하는 경우에는 이슈 번호를 포함한다.
- "[#이슈번호] Title"
- 기능 단위로 PR을 분리 (작업이 너무 크면 나누기)
- 최소 1인 이상의 리뷰어의 코드 리뷰 후 dev 브랜치로 머지
- 충돌이 없고 빌드가 통과된 경우에만 머지 허용
- PR 본문에 해당 작업의 목적과 결과 요약 작성
---
## 4⃣ 작업 프로세스
### 🔹 작업 단위 기준
- 하나의 브랜치는 하나의 기능/이슈 작업 단위로 구성한다.
- 작업 시작 전, Gitea Issue 또는 Notion Task로 정의된 항목을 확인한다.
### 🔹 이슈 추적 방식
- 모든 작업은 Gitea Issue 또는 별도 트래킹 시스템을 통해 관리한다.
- 이슈 번호는 PR 제목에 포함한다.
- 이슈는 작업이 완료되면 반드시 닫는다.
- Closes #42 / Fixes #42 / Resolves #42 등으로 PR 본문에 넣어 닫는 방식도 사용할 수 있다.
### 🔹 커뮤니케이션 흐름
- 작업 시작 → 진행 중 → 완료 상태를 태그나 칸반 보드로 표현한다.
---
## 5⃣ 협업 및 커뮤니케이션
- 추후 팀이 늘어남에 따라 추가 예정
---
## 6⃣ 테스트 및 품질 관리
- 추후 프로젝트의 규모에 따라 추가 예정
---
## 7⃣ 보안 및 인증 관련
### 🔹 보안 관련
- 민감한 정보는 절대 Git에 커밋하지 않는다.
- ./private 폴더를 로컬 저장소에 생성하여 비밀 정보를 관리한다. (ignore 폴더)
- API 인증은 JWT를 사용하며, 모든 API 요청 시 JWT 토큰을 헤더에 포함하여 전송한다.
- FE 에서는 절대 비밀 정보를 노출하지 않도록 한다.
- API 키, 비밀번호 등은 절대 코드에 하드코딩하지 않는다.
- API 키는 환경 변수나 설정 파일을 통해 관리한다.
- API 요청 시 CORS 정책을 준수한다.
- API 서버와 클라이언트 서버의 도메인이 다를 경우 CORS 설정을 통해 허용된 도메인에서만 요청을 받을 수 있도록 한다.
- CORS 설정은 API 서버에서 관리하며, 클라이언트에서는 별도로 설정하지 않는다.
---
## 8⃣ 배포 및 운영
### 🔹 배포 전략
- 배포는 Jenkins를 통해 자동화되어 있으며, Gitea 저장소와 연동되어 특정 브랜치에 대한 변경을 자동 감지하고 실행된다.
- 개발자는 별도의 수동 빌드나 배포를 할 필요 없이, 브랜치 전략과 PR 규칙을 따르면 된다.
### 🔹 브랜치 기반 배포 흐름
|브랜치|용도| 대상 환경|
|:---:|:---:|:----|
|dev|통합 테스트용|Debug 환경 (내부 QA)|
|main|운영 서비스용|Release 환경 (실서비스)|
- `feature/*`, `bugfix/*` 브랜치는 배포되지 않으며, PR을 통해 dev 또는 main 으로 `머지될 때만 배포`가 진행된다.
- 빌드는 .NET 8 기반으로 진행되며, 결과물은 자동으로 컨테이너에서 실행된다.
### 🔹 배포 자동화 요약
- PR 머지 시 Jenkins가 자동으로:
1. 빌드 실행
2. 기존 컨테이너 종료 후 새 컨테이너 실행
- 개발자는 PR만 규칙에 따라 작성하면 자동으로 배포까지 완료된다.
### 🔹 기타 참고 사항
- 환경 설정 및 보안 설정은 팀 내 인프라 관리자가 관리하며, 개발자는 직접 접근하지 않는다.
- Front(WebAssembly)는 별도 서버 없이 백엔드가 static 파일로 제공한다.
- 배포 실패 시 인프라 관리자가 수동 복구하며, 개발자는 따로 조치할 필요 없음
---
## 9⃣ 공통 코드 및 재사용 정책
### 🔹 Service 를 활용한 별도의 계층 구분
- 외부의 API와 통신하는 부분은 ViewModel 에서 직접적인 API 호출이 아닌 별도의 Service를 통해 호출
### 🔹 상태 공유 규칙
- View간 전역 상태를 관리하는 경우에 'AppState' 를 사용하여 관리
- 해당 클래스가 많아질 경우 도메인 접두어를 붙여서 사용
- AppState는 ViewModel과 Service에서 사용 가능
- AppState는 ViewModel과 Service에서 DI를 통해 주입받아 사용 Program.cs 에서 DI를 등록
- appState는 Scoped으로 등록
- AppState는 ViewModel과 Service에서 직접적으로 상태를 변경하지 않도록 작성
- ViewModel과 Service에서 AppState의 상태를 변경하는 경우에는 반드시 AppState의 메서드를 통해서만 변경하도록 작성
- AppState는 ViewModel과 Service에서 직접적으로 상태를 가져오는 경우에는 반드시 AppState의 메서드를 통해서만 가져오도록 작성
- AppState에서 상태를 변경시에 event Action? OnChange 방식을 사용
---
## 🔟 예외 처리 및 로깅
### 🔹 상태 변경과 UI 갱신을 분리
- View.razor.cs 에서 ViewModel을 통해 상태 변경과 함께 View를 다시 그리는것이 아님
- ViewModel에서 상태 변경을 하고 ViewModel의 PropertyChanged 이벤트를 통해 View에 알림
- ViewModel에서 상태 변경시에 INotifyPropertyChanged 방식을 사용
### 🔹 에러 처리
- API 요청 시 에러가 발생할 경우, 에러 메시지를 사용자에게 노출하지 않는다.
- 에러 메시지는 로그에 기록하고, 사용자에게는 일반적인 에러 메시지를 노출한다.
- 예) "서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요."
- API 요청 시 에러가 발생할 경우, 에러 코드를 반환한다.
- 에러 코드는 HTTP 상태 코드와 함께 반환하며, 클라이언트에서는 에러 코드를 기반으로 처리한다.
- 예) 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found 등
- ViewModel에서는 사용자 입력 예외, API 실패처리를 UI와 연결하여 처리한다.
- 공통 예외 응답은 Service에서 처리하며, ViewModel에서는 공통 예외 응답을 사용하여 UI와 연결한다.
- 사용자에 대한 알림 방식은 AlertService를 통해 처리한다.