# PX - RFS Framework 기반 Python 프로젝트
RFS Framework Enterprise Architecture를 따르는 Python FastAPI 프로젝트입니다.
## 📋 개요
이 프로젝트는 RFS Framework의 핵심 원칙을 준수하여 구축되었습니다:
- **Result 패턴**: 예외 대신 안전한 Result 타입 사용
- **헥사고날 아키텍처**: 계층 분리와 의존성 역전
- **함수형 프로그래밍**: 불변성과 순수 함수 선호
- **한글 주석**: 명확한 한국어 문서화
## 🚀 빠른 시작
### 환경 설정
```bash
# 가상환경 생성 및 활성화 (필수!)
python -m venv venv
source venv/bin/activate # macOS/Linux
# 또는 venv\Scripts\activate # Windows
# 의존성 설치
pip install -r requirements-dev.txt
# 개발 서버 실행
uvicorn main:app --reload --host 0.0.0.0 --port 8000
```
### 개발 도구
```bash
# 테스트 실행
pytest
pytest --cov=app --cov-report=html # 커버리지 포함
# 코드 포맷팅 및 검사
black .
isort .
flake8
# RFS Framework 규칙 검증
python scripts/validate_rfs_rules.py --mode strict
```
## 📁 프로젝트 구조
```
px/
├── src/ # 소스 코드 루트
│ ├── api/ # API 계층 (진입점)
│ │ ├── rest/v1/ # REST API v1
│ │ │ ├── controllers/ # HTTP 컨트롤러
│ │ │ ├── routes/ # 라우트 정의
│ │ │ └── middleware/ # API 미들웨어
│ │ └── graphql/ # GraphQL (선택사항)
│ │
│ ├── application/ # 애플리케이션 계층 (유스케이스)
│ │ ├── use_cases/ # 비즈니스 유스케이스
│ │ ├── services/ # 애플리케이션 서비스
│ │ ├── dto/ # 데이터 전송 객체
│ │ └── mappers/ # DTO-Domain 매핑
│ │
│ ├── domain/ # 도메인 계층 (핵심 비즈니스)
│ │ ├── models/ # 도메인 모델
│ │ ├── repositories/ # 리포지토리 인터페이스
│ │ ├── services/ # 도메인 서비스
│ │ └── events/ # 도메인 이벤트
│ │
│ ├── infrastructure/ # 인프라스트럭처 계층
│ │ ├── persistence/ # 데이터 영속성
│ │ ├── messaging/ # 메시징 시스템
│ │ ├── external/ # 외부 서비스 연동
│ │ └── cache/ # 캐싱 계층
│ │
│ ├── shared/ # 공유 모듈
│ │ ├── kernel/ # 핵심 패턴 (Result, Monad)
│ │ ├── exceptions/ # 커스텀 예외
│ │ └── utils/ # 유틸리티
│ │
│ └── config/ # 설정
│ ├── environments/ # 환경별 설정
│ └── dependencies.py # 의존성 주입
│
├── tests/ # 테스트 스위트
├── scripts/ # 운영 스크립트
├── rules/ # RFS 규칙 문서
└── docs/ # 프로젝트 문서
```
## 🔧 RFS Framework 규칙 준수
### ⚠️ 필수 준수 사항
이 프로젝트는 다음 규칙들을 **반드시** 준수해야 합니다:
#### 1. RFS Framework 우선 사용
```python
# ✅ 올바른 방법: Framework 패턴 사용
from rfs.core.result import Result, Success, Failure
def process_user(data: dict) -> Result[User, str]:
if not data:
return Failure("데이터가 없습니다")
return Success(User(**data))
# ❌ 잘못된 방법: 커스텀 구현
def process_user(data):
if not data:
raise ValueError("Invalid data") # 금지!
return User(**data)
```
#### 2. Result 패턴 필수 사용
```python
# ✅ 모든 비즈니스 로직은 Result 반환
async def create_order(data: dict) -> Result[Order, str]:
return (
validate_order_data(data)
.bind(check_inventory)
.bind(process_payment)
.bind(create_order_entity)
)
```
#### 3. 한글 주석 필수
```python
def calculate_total(items: List[Item]) -> Result[Decimal, str]:
"""
주문 아이템들의 총 가격을 계산합니다.
Args:
items: 가격을 계산할 아이템 목록
Returns:
Result[Decimal, str]: 총액 또는 에러 메시지
"""
# 빈 목록 검증
if not items:
return Failure("아이템이 없습니다")
# 총액 계산
total = sum(item.price for item in items)
return Success(total)
```
#### 4. 불변성 유지
```python
from dataclasses import dataclass
@dataclass(frozen=True) # 필수: 불변 객체
class User:
id: str
name: str
email: str
def update_name(self, new_name: str) -> 'User':
"""이름 업데이트 시 새 인스턴스 반환"""
return dataclass.replace(self, name=new_name)
```
#### 5. 타입 힌트 필수
```python
# 모든 함수는 완전한 타입 힌트 포함
def process_payment(
amount: Decimal,
payment_method: PaymentMethod,
user_id: str
) -> Result[Payment, str]:
"""결제를 처리합니다."""
pass
```
### 🔍 규칙 검증
#### 자동 검증 실행
```bash
# 엄격 모드로 모든 규칙 검증
python scripts/validate_rfs_rules.py --mode strict
# 경고 포함 검증
python scripts/validate_rfs_rules.py --mode warning
# JSON 형식 보고서
python scripts/validate_rfs_rules.py --report json --output report.json
# 자동 수정 가능한 항목 확인
python scripts/validate_rfs_rules.py --fix
```
#### Pre-commit 훅 사용
```bash
# Pre-commit 설치 및 설정
pip install pre-commit
pre-commit install
# 수동 실행
pre-commit run --all-files
```
### 📋 개발 체크리스트
#### 코드 작성 전
- [ ] RFS Framework에서 기존 구현 검색
- [ ] Result 패턴 사용 계획
- [ ] 의존성 주입 설계
- [ ] 불변성 유지 방법 계획
#### 코드 작성 중
- [ ] 모든 주석을 한글로 작성
- [ ] 예외 대신 Result 반환
- [ ] 타입 힌트 완전 작성
- [ ] 불변 데이터 구조 사용
#### 코드 작성 후
- [ ] 테스트 작성 (Result 패턴 사용)
- [ ] 자동 검증 실행 및 통과
- [ ] 코드 리뷰 준비
- [ ] 문서 업데이트
## 🧪 테스트
### 테스트 실행
```bash
# 모든 테스트 실행
pytest
# 커버리지 포함
pytest --cov=src --cov-report=html --cov-report=term
# 특정 테스트만 실행
pytest tests/unit/
pytest tests/integration/
pytest tests/e2e/
```
### 테스트 작성 예제
```python
import pytest
from rfs.core.result import Success, Failure
class TestUserService:
@pytest.mark.asyncio
async def test_사용자_생성_성공(self):
"""유효한 데이터로 사용자 생성 시 성공해야 함"""
# Given
user_data = {"email": "test@example.com", "name": "테스트"}
# When
result = await user_service.create_user(user_data)
# Then
assert result.is_success()
user = result.unwrap()
assert user.email == "test@example.com"
assert user.name == "테스트"
```
## 📚 추가 문서
- [필수 규칙 가이드](rules/00-mandatory-rules.md) - 절대 준수해야 할 규칙들
- [통합 규칙 가이드](rules/10-rule-integration.md) - 모든 규칙의 통합 적용 방법
- [Result 패턴](rules/01-result-pattern.md) - 안전한 에러 처리
- [함수형 프로그래밍](rules/02-functional-programming.md) - 불변성과 순수 함수
- [헥사고날 아키텍처](rules/04-hexagonal-architecture.md) - 계층 구조
- [한글 주석 가이드](rules/09-korean-comments.md) - 명확한 문서화
## 🤝 기여하기
### 기여 절차
1. **가상환경 활성화 필수**: `source venv/bin/activate`
2. **RFS 규칙 숙지**: [필수 규칙](rules/00-mandatory-rules.md) 읽기
3. **규칙 검증 통과**: `python scripts/validate_rfs_rules.py --mode strict`
4. **테스트 작성 및 통과**: `pytest`
5. **Pre-commit 훅 통과**: `pre-commit run --all-files`
### 코드 리뷰 기준
- ✅ RFS Framework 패턴 사용
- ✅ Result 패턴으로 에러 처리
- ✅ 한글 주석 및 문서화
- ✅ 완전한 타입 힌트
- ✅ 불변성 유지
- ✅ 테스트 커버리지 80% 이상
## 📞 지원
- **이슈 보고**: GitHub Issues 사용
- **질문**: Discussions 섹션 활용
- **긴급 문제**: 팀 채널로 연락
---
> 💡 **중요**: 이 프로젝트는 RFS Framework 규칙을 엄격히 준수합니다.
> 모든 기여자는 개발 전에 [필수 규칙](rules/00-mandatory-rules.md)을 반드시 숙지해주세요.
Raw data
{
"_id": null,
"home_page": null,
"name": "px-rfs-project",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "fastapi, rfs-framework, enterprise, api, cosmos",
"author": null,
"author_email": "Cosmos Team <dev@cosmos.com>",
"download_url": "https://files.pythonhosted.org/packages/8d/da/2fc01e1a9965c70125140b371dc759a82e5b3e262a4ec2e992422c947b7b/px_rfs_project-1.0.0.tar.gz",
"platform": null,
"description": "# PX - RFS Framework \uae30\ubc18 Python \ud504\ub85c\uc81d\ud2b8\n\nRFS Framework Enterprise Architecture\ub97c \ub530\ub974\ub294 Python FastAPI \ud504\ub85c\uc81d\ud2b8\uc785\ub2c8\ub2e4.\n\n## \ud83d\udccb \uac1c\uc694\n\n\uc774 \ud504\ub85c\uc81d\ud2b8\ub294 RFS Framework\uc758 \ud575\uc2ec \uc6d0\uce59\uc744 \uc900\uc218\ud558\uc5ec \uad6c\ucd95\ub418\uc5c8\uc2b5\ub2c8\ub2e4:\n- **Result \ud328\ud134**: \uc608\uc678 \ub300\uc2e0 \uc548\uc804\ud55c Result \ud0c0\uc785 \uc0ac\uc6a9\n- **\ud5e5\uc0ac\uace0\ub0a0 \uc544\ud0a4\ud14d\ucc98**: \uacc4\uce35 \ubd84\ub9ac\uc640 \uc758\uc874\uc131 \uc5ed\uc804\n- **\ud568\uc218\ud615 \ud504\ub85c\uadf8\ub798\ubc0d**: \ubd88\ubcc0\uc131\uacfc \uc21c\uc218 \ud568\uc218 \uc120\ud638\n- **\ud55c\uae00 \uc8fc\uc11d**: \uba85\ud655\ud55c \ud55c\uad6d\uc5b4 \ubb38\uc11c\ud654\n\n## \ud83d\ude80 \ube60\ub978 \uc2dc\uc791\n\n### \ud658\uacbd \uc124\uc815\n```bash\n# \uac00\uc0c1\ud658\uacbd \uc0dd\uc131 \ubc0f \ud65c\uc131\ud654 (\ud544\uc218!)\npython -m venv venv\nsource venv/bin/activate # macOS/Linux\n# \ub610\ub294 venv\\Scripts\\activate # Windows\n\n# \uc758\uc874\uc131 \uc124\uce58\npip install -r requirements-dev.txt\n\n# \uac1c\ubc1c \uc11c\ubc84 \uc2e4\ud589\nuvicorn main:app --reload --host 0.0.0.0 --port 8000\n```\n\n### \uac1c\ubc1c \ub3c4\uad6c\n```bash\n# \ud14c\uc2a4\ud2b8 \uc2e4\ud589\npytest\npytest --cov=app --cov-report=html # \ucee4\ubc84\ub9ac\uc9c0 \ud3ec\ud568\n\n# \ucf54\ub4dc \ud3ec\ub9f7\ud305 \ubc0f \uac80\uc0ac\nblack .\nisort .\nflake8\n\n# RFS Framework \uaddc\uce59 \uac80\uc99d\npython scripts/validate_rfs_rules.py --mode strict\n```\n\n## \ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 \uad6c\uc870\n\n```\npx/\n\u251c\u2500\u2500 src/ # \uc18c\uc2a4 \ucf54\ub4dc \ub8e8\ud2b8\n\u2502 \u251c\u2500\u2500 api/ # API \uacc4\uce35 (\uc9c4\uc785\uc810)\n\u2502 \u2502 \u251c\u2500\u2500 rest/v1/ # REST API v1\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 controllers/ # HTTP \ucee8\ud2b8\ub864\ub7ec\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 routes/ # \ub77c\uc6b0\ud2b8 \uc815\uc758\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 middleware/ # API \ubbf8\ub4e4\uc6e8\uc5b4\n\u2502 \u2502 \u2514\u2500\u2500 graphql/ # GraphQL (\uc120\ud0dd\uc0ac\ud56d)\n\u2502 \u2502\n\u2502 \u251c\u2500\u2500 application/ # \uc560\ud50c\ub9ac\ucf00\uc774\uc158 \uacc4\uce35 (\uc720\uc2a4\ucf00\uc774\uc2a4)\n\u2502 \u2502 \u251c\u2500\u2500 use_cases/ # \ube44\uc988\ub2c8\uc2a4 \uc720\uc2a4\ucf00\uc774\uc2a4\n\u2502 \u2502 \u251c\u2500\u2500 services/ # \uc560\ud50c\ub9ac\ucf00\uc774\uc158 \uc11c\ube44\uc2a4\n\u2502 \u2502 \u251c\u2500\u2500 dto/ # \ub370\uc774\ud130 \uc804\uc1a1 \uac1d\uccb4\n\u2502 \u2502 \u2514\u2500\u2500 mappers/ # DTO-Domain \ub9e4\ud551\n\u2502 \u2502\n\u2502 \u251c\u2500\u2500 domain/ # \ub3c4\uba54\uc778 \uacc4\uce35 (\ud575\uc2ec \ube44\uc988\ub2c8\uc2a4)\n\u2502 \u2502 \u251c\u2500\u2500 models/ # \ub3c4\uba54\uc778 \ubaa8\ub378\n\u2502 \u2502 \u251c\u2500\u2500 repositories/ # \ub9ac\ud3ec\uc9c0\ud1a0\ub9ac \uc778\ud130\ud398\uc774\uc2a4\n\u2502 \u2502 \u251c\u2500\u2500 services/ # \ub3c4\uba54\uc778 \uc11c\ube44\uc2a4\n\u2502 \u2502 \u2514\u2500\u2500 events/ # \ub3c4\uba54\uc778 \uc774\ubca4\ud2b8\n\u2502 \u2502\n\u2502 \u251c\u2500\u2500 infrastructure/ # \uc778\ud504\ub77c\uc2a4\ud2b8\ub7ed\ucc98 \uacc4\uce35\n\u2502 \u2502 \u251c\u2500\u2500 persistence/ # \ub370\uc774\ud130 \uc601\uc18d\uc131\n\u2502 \u2502 \u251c\u2500\u2500 messaging/ # \uba54\uc2dc\uc9d5 \uc2dc\uc2a4\ud15c\n\u2502 \u2502 \u251c\u2500\u2500 external/ # \uc678\ubd80 \uc11c\ube44\uc2a4 \uc5f0\ub3d9\n\u2502 \u2502 \u2514\u2500\u2500 cache/ # \uce90\uc2f1 \uacc4\uce35\n\u2502 \u2502\n\u2502 \u251c\u2500\u2500 shared/ # \uacf5\uc720 \ubaa8\ub4c8\n\u2502 \u2502 \u251c\u2500\u2500 kernel/ # \ud575\uc2ec \ud328\ud134 (Result, Monad)\n\u2502 \u2502 \u251c\u2500\u2500 exceptions/ # \ucee4\uc2a4\ud140 \uc608\uc678\n\u2502 \u2502 \u2514\u2500\u2500 utils/ # \uc720\ud2f8\ub9ac\ud2f0\n\u2502 \u2502\n\u2502 \u2514\u2500\u2500 config/ # \uc124\uc815\n\u2502 \u251c\u2500\u2500 environments/ # \ud658\uacbd\ubcc4 \uc124\uc815\n\u2502 \u2514\u2500\u2500 dependencies.py # \uc758\uc874\uc131 \uc8fc\uc785\n\u2502\n\u251c\u2500\u2500 tests/ # \ud14c\uc2a4\ud2b8 \uc2a4\uc704\ud2b8\n\u251c\u2500\u2500 scripts/ # \uc6b4\uc601 \uc2a4\ud06c\ub9bd\ud2b8\n\u251c\u2500\u2500 rules/ # RFS \uaddc\uce59 \ubb38\uc11c\n\u2514\u2500\u2500 docs/ # \ud504\ub85c\uc81d\ud2b8 \ubb38\uc11c\n```\n\n## \ud83d\udd27 RFS Framework \uaddc\uce59 \uc900\uc218\n\n### \u26a0\ufe0f \ud544\uc218 \uc900\uc218 \uc0ac\ud56d\n\n\uc774 \ud504\ub85c\uc81d\ud2b8\ub294 \ub2e4\uc74c \uaddc\uce59\ub4e4\uc744 **\ubc18\ub4dc\uc2dc** \uc900\uc218\ud574\uc57c \ud569\ub2c8\ub2e4:\n\n#### 1. RFS Framework \uc6b0\uc120 \uc0ac\uc6a9\n```python\n# \u2705 \uc62c\ubc14\ub978 \ubc29\ubc95: Framework \ud328\ud134 \uc0ac\uc6a9\nfrom rfs.core.result import Result, Success, Failure\n\ndef process_user(data: dict) -> Result[User, str]:\n if not data:\n return Failure(\"\ub370\uc774\ud130\uac00 \uc5c6\uc2b5\ub2c8\ub2e4\")\n return Success(User(**data))\n\n# \u274c \uc798\ubabb\ub41c \ubc29\ubc95: \ucee4\uc2a4\ud140 \uad6c\ud604\ndef process_user(data):\n if not data:\n raise ValueError(\"Invalid data\") # \uae08\uc9c0!\n return User(**data)\n```\n\n#### 2. Result \ud328\ud134 \ud544\uc218 \uc0ac\uc6a9\n```python\n# \u2705 \ubaa8\ub4e0 \ube44\uc988\ub2c8\uc2a4 \ub85c\uc9c1\uc740 Result \ubc18\ud658\nasync def create_order(data: dict) -> Result[Order, str]:\n return (\n validate_order_data(data)\n .bind(check_inventory)\n .bind(process_payment)\n .bind(create_order_entity)\n )\n```\n\n#### 3. \ud55c\uae00 \uc8fc\uc11d \ud544\uc218\n```python\ndef calculate_total(items: List[Item]) -> Result[Decimal, str]:\n \"\"\"\n \uc8fc\ubb38 \uc544\uc774\ud15c\ub4e4\uc758 \ucd1d \uac00\uaca9\uc744 \uacc4\uc0b0\ud569\ub2c8\ub2e4.\n \n Args:\n items: \uac00\uaca9\uc744 \uacc4\uc0b0\ud560 \uc544\uc774\ud15c \ubaa9\ub85d\n \n Returns:\n Result[Decimal, str]: \ucd1d\uc561 \ub610\ub294 \uc5d0\ub7ec \uba54\uc2dc\uc9c0\n \"\"\"\n # \ube48 \ubaa9\ub85d \uac80\uc99d\n if not items:\n return Failure(\"\uc544\uc774\ud15c\uc774 \uc5c6\uc2b5\ub2c8\ub2e4\")\n \n # \ucd1d\uc561 \uacc4\uc0b0\n total = sum(item.price for item in items)\n return Success(total)\n```\n\n#### 4. \ubd88\ubcc0\uc131 \uc720\uc9c0\n```python\nfrom dataclasses import dataclass\n\n@dataclass(frozen=True) # \ud544\uc218: \ubd88\ubcc0 \uac1d\uccb4\nclass User:\n id: str\n name: str\n email: str\n \n def update_name(self, new_name: str) -> 'User':\n \"\"\"\uc774\ub984 \uc5c5\ub370\uc774\ud2b8 \uc2dc \uc0c8 \uc778\uc2a4\ud134\uc2a4 \ubc18\ud658\"\"\"\n return dataclass.replace(self, name=new_name)\n```\n\n#### 5. \ud0c0\uc785 \ud78c\ud2b8 \ud544\uc218\n```python\n# \ubaa8\ub4e0 \ud568\uc218\ub294 \uc644\uc804\ud55c \ud0c0\uc785 \ud78c\ud2b8 \ud3ec\ud568\ndef process_payment(\n amount: Decimal, \n payment_method: PaymentMethod,\n user_id: str\n) -> Result[Payment, str]:\n \"\"\"\uacb0\uc81c\ub97c \ucc98\ub9ac\ud569\ub2c8\ub2e4.\"\"\"\n pass\n```\n\n### \ud83d\udd0d \uaddc\uce59 \uac80\uc99d\n\n#### \uc790\ub3d9 \uac80\uc99d \uc2e4\ud589\n```bash\n# \uc5c4\uaca9 \ubaa8\ub4dc\ub85c \ubaa8\ub4e0 \uaddc\uce59 \uac80\uc99d\npython scripts/validate_rfs_rules.py --mode strict\n\n# \uacbd\uace0 \ud3ec\ud568 \uac80\uc99d\npython scripts/validate_rfs_rules.py --mode warning\n\n# JSON \ud615\uc2dd \ubcf4\uace0\uc11c\npython scripts/validate_rfs_rules.py --report json --output report.json\n\n# \uc790\ub3d9 \uc218\uc815 \uac00\ub2a5\ud55c \ud56d\ubaa9 \ud655\uc778\npython scripts/validate_rfs_rules.py --fix\n```\n\n#### Pre-commit \ud6c5 \uc0ac\uc6a9\n```bash\n# Pre-commit \uc124\uce58 \ubc0f \uc124\uc815\npip install pre-commit\npre-commit install\n\n# \uc218\ub3d9 \uc2e4\ud589\npre-commit run --all-files\n```\n\n### \ud83d\udccb \uac1c\ubc1c \uccb4\ud06c\ub9ac\uc2a4\ud2b8\n\n#### \ucf54\ub4dc \uc791\uc131 \uc804\n- [ ] RFS Framework\uc5d0\uc11c \uae30\uc874 \uad6c\ud604 \uac80\uc0c9\n- [ ] Result \ud328\ud134 \uc0ac\uc6a9 \uacc4\ud68d\n- [ ] \uc758\uc874\uc131 \uc8fc\uc785 \uc124\uacc4\n- [ ] \ubd88\ubcc0\uc131 \uc720\uc9c0 \ubc29\ubc95 \uacc4\ud68d\n\n#### \ucf54\ub4dc \uc791\uc131 \uc911 \n- [ ] \ubaa8\ub4e0 \uc8fc\uc11d\uc744 \ud55c\uae00\ub85c \uc791\uc131\n- [ ] \uc608\uc678 \ub300\uc2e0 Result \ubc18\ud658\n- [ ] \ud0c0\uc785 \ud78c\ud2b8 \uc644\uc804 \uc791\uc131\n- [ ] \ubd88\ubcc0 \ub370\uc774\ud130 \uad6c\uc870 \uc0ac\uc6a9\n\n#### \ucf54\ub4dc \uc791\uc131 \ud6c4\n- [ ] \ud14c\uc2a4\ud2b8 \uc791\uc131 (Result \ud328\ud134 \uc0ac\uc6a9)\n- [ ] \uc790\ub3d9 \uac80\uc99d \uc2e4\ud589 \ubc0f \ud1b5\uacfc\n- [ ] \ucf54\ub4dc \ub9ac\ubdf0 \uc900\ube44\n- [ ] \ubb38\uc11c \uc5c5\ub370\uc774\ud2b8\n\n## \ud83e\uddea \ud14c\uc2a4\ud2b8\n\n### \ud14c\uc2a4\ud2b8 \uc2e4\ud589\n```bash\n# \ubaa8\ub4e0 \ud14c\uc2a4\ud2b8 \uc2e4\ud589\npytest\n\n# \ucee4\ubc84\ub9ac\uc9c0 \ud3ec\ud568\npytest --cov=src --cov-report=html --cov-report=term\n\n# \ud2b9\uc815 \ud14c\uc2a4\ud2b8\ub9cc \uc2e4\ud589\npytest tests/unit/\npytest tests/integration/\npytest tests/e2e/\n```\n\n### \ud14c\uc2a4\ud2b8 \uc791\uc131 \uc608\uc81c\n```python\nimport pytest\nfrom rfs.core.result import Success, Failure\n\nclass TestUserService:\n @pytest.mark.asyncio\n async def test_\uc0ac\uc6a9\uc790_\uc0dd\uc131_\uc131\uacf5(self):\n \"\"\"\uc720\ud6a8\ud55c \ub370\uc774\ud130\ub85c \uc0ac\uc6a9\uc790 \uc0dd\uc131 \uc2dc \uc131\uacf5\ud574\uc57c \ud568\"\"\"\n # Given\n user_data = {\"email\": \"test@example.com\", \"name\": \"\ud14c\uc2a4\ud2b8\"}\n \n # When\n result = await user_service.create_user(user_data)\n \n # Then\n assert result.is_success()\n user = result.unwrap()\n assert user.email == \"test@example.com\"\n assert user.name == \"\ud14c\uc2a4\ud2b8\"\n```\n\n## \ud83d\udcda \ucd94\uac00 \ubb38\uc11c\n\n- [\ud544\uc218 \uaddc\uce59 \uac00\uc774\ub4dc](rules/00-mandatory-rules.md) - \uc808\ub300 \uc900\uc218\ud574\uc57c \ud560 \uaddc\uce59\ub4e4\n- [\ud1b5\ud569 \uaddc\uce59 \uac00\uc774\ub4dc](rules/10-rule-integration.md) - \ubaa8\ub4e0 \uaddc\uce59\uc758 \ud1b5\ud569 \uc801\uc6a9 \ubc29\ubc95\n- [Result \ud328\ud134](rules/01-result-pattern.md) - \uc548\uc804\ud55c \uc5d0\ub7ec \ucc98\ub9ac\n- [\ud568\uc218\ud615 \ud504\ub85c\uadf8\ub798\ubc0d](rules/02-functional-programming.md) - \ubd88\ubcc0\uc131\uacfc \uc21c\uc218 \ud568\uc218\n- [\ud5e5\uc0ac\uace0\ub0a0 \uc544\ud0a4\ud14d\ucc98](rules/04-hexagonal-architecture.md) - \uacc4\uce35 \uad6c\uc870\n- [\ud55c\uae00 \uc8fc\uc11d \uac00\uc774\ub4dc](rules/09-korean-comments.md) - \uba85\ud655\ud55c \ubb38\uc11c\ud654\n\n## \ud83e\udd1d \uae30\uc5ec\ud558\uae30\n\n### \uae30\uc5ec \uc808\ucc28\n1. **\uac00\uc0c1\ud658\uacbd \ud65c\uc131\ud654 \ud544\uc218**: `source venv/bin/activate`\n2. **RFS \uaddc\uce59 \uc219\uc9c0**: [\ud544\uc218 \uaddc\uce59](rules/00-mandatory-rules.md) \uc77d\uae30\n3. **\uaddc\uce59 \uac80\uc99d \ud1b5\uacfc**: `python scripts/validate_rfs_rules.py --mode strict`\n4. **\ud14c\uc2a4\ud2b8 \uc791\uc131 \ubc0f \ud1b5\uacfc**: `pytest`\n5. **Pre-commit \ud6c5 \ud1b5\uacfc**: `pre-commit run --all-files`\n\n### \ucf54\ub4dc \ub9ac\ubdf0 \uae30\uc900\n- \u2705 RFS Framework \ud328\ud134 \uc0ac\uc6a9\n- \u2705 Result \ud328\ud134\uc73c\ub85c \uc5d0\ub7ec \ucc98\ub9ac\n- \u2705 \ud55c\uae00 \uc8fc\uc11d \ubc0f \ubb38\uc11c\ud654\n- \u2705 \uc644\uc804\ud55c \ud0c0\uc785 \ud78c\ud2b8\n- \u2705 \ubd88\ubcc0\uc131 \uc720\uc9c0\n- \u2705 \ud14c\uc2a4\ud2b8 \ucee4\ubc84\ub9ac\uc9c0 80% \uc774\uc0c1\n\n## \ud83d\udcde \uc9c0\uc6d0\n\n- **\uc774\uc288 \ubcf4\uace0**: GitHub Issues \uc0ac\uc6a9\n- **\uc9c8\ubb38**: Discussions \uc139\uc158 \ud65c\uc6a9\n- **\uae34\uae09 \ubb38\uc81c**: \ud300 \ucc44\ub110\ub85c \uc5f0\ub77d\n\n---\n\n> \ud83d\udca1 **\uc911\uc694**: \uc774 \ud504\ub85c\uc81d\ud2b8\ub294 RFS Framework \uaddc\uce59\uc744 \uc5c4\uaca9\ud788 \uc900\uc218\ud569\ub2c8\ub2e4. \n> \ubaa8\ub4e0 \uae30\uc5ec\uc790\ub294 \uac1c\ubc1c \uc804\uc5d0 [\ud544\uc218 \uaddc\uce59](rules/00-mandatory-rules.md)\uc744 \ubc18\ub4dc\uc2dc \uc219\uc9c0\ud574\uc8fc\uc138\uc694.\n",
"bugtrack_url": null,
"license": null,
"summary": "RFS Framework \uae30\ubc18 \uc5d4\ud130\ud504\ub77c\uc774\uc988 Python \uc560\ud50c\ub9ac\ucf00\uc774\uc158",
"version": "1.0.0",
"project_urls": {
"Bug Tracker": "https://github.com/cosmos-team/px-rfs-project/issues",
"Changelog": "https://github.com/cosmos-team/px-rfs-project/blob/main/CHANGELOG.md",
"Documentation": "https://cosmos-team.github.io/px-rfs-project/",
"Homepage": "https://github.com/cosmos-team/px-rfs-project",
"Repository": "https://github.com/cosmos-team/px-rfs-project.git"
},
"split_keywords": [
"fastapi",
" rfs-framework",
" enterprise",
" api",
" cosmos"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "6f1640137e80d63ccb699e8f89eb51c1f48b3c10be49a24a794c016654b0c39a",
"md5": "b633317850583790c2f70c6b0fb690d9",
"sha256": "e05d1c57b914306a869d5cb1d3fdd9fcaa8c2c9752a56a3aed495b1eabba30ae"
},
"downloads": -1,
"filename": "px_rfs_project-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "b633317850583790c2f70c6b0fb690d9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 91760,
"upload_time": "2025-08-27T06:19:52",
"upload_time_iso_8601": "2025-08-27T06:19:52.881879Z",
"url": "https://files.pythonhosted.org/packages/6f/16/40137e80d63ccb699e8f89eb51c1f48b3c10be49a24a794c016654b0c39a/px_rfs_project-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "8dda2fc01e1a9965c70125140b371dc759a82e5b3e262a4ec2e992422c947b7b",
"md5": "d51ebcff271e04b2584dec7f223cfc8d",
"sha256": "2c3af6e4ca748d91ed79c3618911e2fdd43e509245b6ef1c9a7ffff02643d84b"
},
"downloads": -1,
"filename": "px_rfs_project-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "d51ebcff271e04b2584dec7f223cfc8d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 75437,
"upload_time": "2025-08-27T06:19:55",
"upload_time_iso_8601": "2025-08-27T06:19:55.096057Z",
"url": "https://files.pythonhosted.org/packages/8d/da/2fc01e1a9965c70125140b371dc759a82e5b3e262a4ec2e992422c947b7b/px_rfs_project-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-27 06:19:55",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "cosmos-team",
"github_project": "px-rfs-project",
"github_not_found": true,
"lcname": "px-rfs-project"
}