forked from AcaMate/AcaMate_Web
[📝] Project Rule 생성
This commit is contained in:
parent
f28e292d1a
commit
13924e2903
200
Documents/Project RULE 10.md
Normal file
200
Documents/Project RULE 10.md
Normal file
|
@ -0,0 +1,200 @@
|
|||
# Coding RULE 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를 통해 처리한다.
|
60
README.md
60
README.md
|
@ -1,5 +1,12 @@
|
|||
# Web Client
|
||||
|
||||
## Project Rule
|
||||
|
||||
### [[📚 PROJECT RULE (클릭시 이동)]](Documents/Project%20RULE%2010.md)
|
||||
***필수 사항은 반드시 지켜주세요!***
|
||||
|
||||
---
|
||||
|
||||
## Development Environment
|
||||
### Skill
|
||||
- Blazor WebAssembly
|
||||
|
@ -9,57 +16,4 @@
|
|||
|
||||
---
|
||||
|
||||
## Project Rule
|
||||
### 구조 < MVVM >
|
||||
#### Model
|
||||
- 데이터를 정의하는 역할
|
||||
- ./Program/Models 에 위치
|
||||
- 별도의 DTO 와 엔티티의 클래스로 구성
|
||||
#### View
|
||||
- UI를 정의하는 역할
|
||||
- ./Program/Pages 에 .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 코드에 의존하지 않도록 작성
|
||||
|
||||
### 그 외
|
||||
#### 1. 네임스페이스 구조
|
||||
- 폴더 구조와 네임스페이스는 반드시 일치해야 함
|
||||
```
|
||||
/Program/Pages/Login.razor
|
||||
namespace Front.Program.Pages;
|
||||
```
|
||||
#### 2. Service 를 활용한 별도의 계층 구분
|
||||
- 외부의 API와 통신하는 부분은 ViewModel 에서 직접적인 API 호출이 아닌 별도의 Service를 통해 호출
|
||||
|
||||
#### 3. 상태 변경과 UI 갱신을 분리
|
||||
- View.razor.cs 에서 ViewModel을 통해 상태 변경과 함께 View를 다시 그리는것이 아님
|
||||
- ViewModel에서 상태 변경을 하고 ViewModel의 PropertyChanged 이벤트를 통해 View에 알림
|
||||
- ViewModle에서 상태 변경시에 INotifyPropertyChanged 방식을 사용
|
||||
|
||||
#### 4. 상태 공유 규칙
|
||||
- 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 방식을 사용
|
||||
|
||||
#### 5. DI
|
||||
- ViewModel 과 Service는 DI를 통해 주입받아 사용하며 Program.cs 에서 DI를 등록
|
||||
- ViewModel은 가급적으로 transient로 등록
|
||||
- 하지만 한 View에서 여러 컴포넌트가 하나의 상태를 공유해야 할 경우에는 Scoped로 등록
|
||||
- Service는 Scoped으로 등록
|
||||
- Service는 ViewModel과 다르게 여러 컴포넌트에서 같은 Service를 사용해야 하는 경우가 많기 때문에 Scoped으로 등록
|
||||
|
|
Loading…
Reference in New Issue
Block a user