[파이썬] AI 활용 웹 서비스 개발 기록 : 6 scheme_files 설명
이전 내용
[파이썬] AI 활용 웹 서비스 개발 기록 : 5 models_dir 설명
이전 내용 [파이썬] AI 활용 웹 서비스 개발 기록 : 4 frontend 설명이전 내용 [파이썬] AI 활용 웹 서비스 개발 기록 : 3 emails 설명이전 내용 [파이썬] AI 활용 웹 서비스 개발 기록 : 2 controllers 설명이전
puppy-foot-it.tistory.com
전체 디렉터리 구조
- 기술 스택
- FastAPI (비동기 REST API)
- SQLAlchemy (ORM)
- Pydantic (입력값 검증)
- PostgreSQL (RDBMS)
- 로깅 시스템 (logger): logging 모듈 기반 로그 기록
- 비밀번호 해싱: Passlib (bcrypt)
- 이메일 처리: SMTP + 커스텀 EmailService
- 유효성 검사: re 정규표현식, 수동 로직
- 백그라운드 작업: BackgroundTasks
- 세션 처리: FastAPI session middleware
- 세션 상태 관리: st.session_state
- API 키 관리: dotenv (.env), st.secrets
- 구현 의도
- 단순한 CRUD API를 넘어서 실서비스에서 필요한 유효성 검사, 예외 처리, 중복 방지 등 실제 운영 환경에서 중요한 요소들을 고려해 설계.
- 실무에서 바로 사용 가능한 사용자 인증 API를 처음부터 끝까지 설계 및 개발
- DB 설계, 암호화, 유효성 검사, 예외처리, 이메일 전송 등 실무 요구 사항 반영
- 보안 및 사용자 경험을 모두 고려한 구조라는 점에서 팀 프로젝트 혹은 SaaS 백엔드 개발에 바로 투입 가능
디렉터리 구조 5: scheme_files
- 아이, 사용자, 컨텐츠 관련 클래스
- pydantic을 사용한 아이, 사용자, 컨텐츠 관련 데이터 검증 코드 구현
◆ babies_schemes.py
- Baby(아이) 관련 API 요청 및 응답 데이터의 구조를 정의하고, 유효성 검증
- FastAPI와 연동하여 요청 데이터 검증 및 문서화 (swagger에 자동 적용됨)
[주요 기능]
모델 이름 | 목적 | 주요 필드 | 설명 |
CreateBaby | 아이 생성 요청 시 사용 | user_id, baby_name, baby_gender, baby_bday | 입력값 검증 및 예시 설정 포함 |
BabyResponse | 아이 조회 응답 시 사용 | id, user_id, baby_name | API 응답 모델로 사용 |
DeleteBaby | 아이 삭제 요청 시 사용 | user_id, baby_name | 삭제를 위한 최소 정보 전달 구조 |
[고도화 아이디어]
아이디어 | 내용 | 기대 효과 |
날짜 유효성 | baby_bday에 미래/과거 여부 체크 | 사용자 입력 오류 방지 |
응답 모델 보완 | baby_gender, baby_bday도 BabyResponse에 포함 | 프론트엔드에 더 많은 정보 제공 |
권한 체크 로직 추가 | DeleteBaby에 auth_token 등 추가 고려 | 보안 강화 |
설명/예시 확장 | 각 필드에 설명(Field(..., description="...")) 추가 | API 문서(예: Swagger) 가독성 향상 |
◆ stories_schemes.py
- 동화 생성 및 응답 관련 Pydantic 모델
- 동화 생성, 저장, 응답 및 콘텐츠 생성 요청에 대한 데이터 구조 정의
- FastAPI 서버에서 사용자 요청의 유효성 검증 및 응답 구조 통일
[주요 기능 및 역할]
클래스 이름 | 용도 | 주요 필드 | 설명 |
StoryResponse | 동화 조회 응답용 | id, theme, voice, content, image, bw_image, created_at 등 | DB에서 가져온 Story를 프론트로 전달할 때 사용 |
StoryRequest | 동화 생성 요청 | name, theme | 동화 제목 및 테마 기반 생성 요청 |
SaveStoryRequest | 동화 저장 요청 | user_id, theme, voice, content, image, bw_image | 동화를 DB에 저장하기 위한 요청 |
TTSRequest | 음성 생성 요청 | text, voice, speed | 텍스트를 TTS로 변환하는 요청 |
ImageRequest | 이미지 생성 요청 | text | 동화 내용을 기반으로 이미지 생성 요청 |
MusicRequest | 음악 검색 요청 | theme | 테마에 맞는 자장가 음악 검색 |
VideoRequest | 영상 검색 요청 | theme | 테마에 맞는 유튜브 영상 검색 |
[고도화 아이디어]
아이디어 | 내용 | 기대 효과 |
Field로 문서화 강화 | 각 필드에 Field(..., description=..., example=...) 추가 | Swagger 문서 가독성 향상 |
Enum 클래스 사용 | theme, voice, gender 등에 Enum 사용 | 허용값 명시로 안정성 강화 |
◆ users_schemes.py
- 사용자 회원가입, 로그인, 비밀번호 변경, 사용자 정보 조회 요청에 사용되는 데이터 검증 및 직렬화 모델 정의
- Pydantic, EmailStr, BaseModel 상속 구조
[주요 클래스 기능]
클래스 이름 | 역할 및 목적 | 특징 |
UserCreate | 회원가입 요청 시 입력 데이터 검증 | 이메일 형식 검증 포함, 비밀번호 확인 필드 존재 |
UserLogin | 로그인 요청 시 데이터 검증 | 최소한의 필수 필드 포함 (username, password) |
UserUpdate | 비밀번호 변경 시 데이터 검증 | 기존 비밀번호와 새 비밀번호 필드 존재 |
UserResponse | 사용자 정보 응답용 모델 | DB에서 조회한 사용자 정보 반환용, Config: from_attributes=True 사용 |
UserIdRequest | 사용자 ID 기반 요청 처리용 | 삭제/조회 요청 시 유용 |
[고도화 아이디어]
아이디어 | 내용 | 기대 효과 |
Field() 사용 | Field(..., description="설명", example="test@example.com") 형태로 문서화 | Swagger 문서 자동화 및 가독성 향상 |
검증 로직 클래스화 | @validator()를 활용해 password == password_confirm 검사 | API 요청 단에서 에러 사전 방지 |
▶ 비밀번호 검증 로직의 경우, 현재 users_controller.py 파일에 회원가입 라우터에 구현되어 있으나,
이를 users_chemes.py의 클래스 내에 구현하는 것이 유지보수에 더 용이할 것으로 보임.
★ 참고: users_controller.py의 회원가입 관련 로직
# 회원가입
@router.post("/signup")
async def signup(signup_data: UserCreate, background_tasks: BackgroundTasks, db:Session=Depends(get_db)):
logger.info(f"회원 가입 요청: 사용자 이름 {signup_data.username}, 이메일: {signup_data.email}")
# ID 규칙 확인
if not re.fullmatch(r"[a-z0-9]+", signup_data.username):
logger.warning("회원 가입 실패: 사용자 규칙 위반")
raise HTTPException(status_code=400, detail="사용자 이름은 영어 소문자와 숫자로만 구성되어야 합니다.")
# 비밀번호 규칙 확인
if not password_regex.match(signup_data.password):
logger.warning("회원 가입 실패: 비밀번호 규칙 위반")
raise HTTPException(status_code=400, detail="비밀번호는 최소 10자 이상이며, 대문자, 소문자, 숫자 및 특수문자가 포함돼야 합니다.")
# 비밀번호 확인 일치 검사
if signup_data.password != signup_data.password_confirm:
logger.warning("비밀번호가 일치하지 않습니다.")
raise HTTPException(status_code=400, detail="비밀번호가 서로 일치하지 않습니다.")
# username 중복 확인
existing_user = db.query(User).filter(User.username == signup_data.username).first()
if existing_user:
logger.warning(f"회원 가입 실패: 이미 존재하는 사용자 이름 - {signup_data.username}")
raise HTTPException(status_code=400, detail="이미 존재하는 사용자 이름입니다.")
# nickname 중복 확인
existing_nick = db.query(User).filter(User.nickname == signup_data.nickname).first()
if existing_nick:
logger.warning(f"회원 가입 실패: 이미 존재하는 닉네임 - {signup_data.nickname}")
raise HTTPException(status_code=400, detail="이미 존재하는 닉네임입니다.")
# 모든 조건 만족 시
hashed_password = get_password_hash(signup_data.password) # 비밀번호 해시
# 기본 role_id 설정 (예: 일반 사용자)
DEFAULT_ROLE_ID = 1
new_user = User(username=signup_data.username,
nickname=signup_data.nickname,
email = signup_data.email,
hashed_password=hashed_password,
role_id=DEFAULT_ROLE_ID
)
db.add(new_user)
logger.info(f"{new_user.username} 사용자가 데이터베이스에 추가 되었습니다.")
try:
db.commit()
logger.info("데이터베이스에 새로운 사용자가 추가되었습니다.")
except Exception as e:
db.rollback() # 에러 발생 시 롤백
logger.error(f"회원 가입 오류: {e}") # 에러 내용 출력
raise HTTPException(status_code=500, detail="회원 가입 실패. 다시 시도해 주세요")
db.refresh(new_user)
# 백그라운드 작업 등록
background_tasks.add_task(send_welcome_email, new_user.email)
logger.info(f"회원 가입 후 사용자 {new_user.username}에게 환영 이메일 발송")
return {"message": "회원가입을 성공하였습니다. 이메일을 확인해 주세요."}
다음 내용
[파이썬] AI 활용 웹 서비스 개발 기록 : 7 main / ai_server
이전 내용 [파이썬] AI 활용 웹 서비스 개발 기록 : 6 scheme_files이전 내용 [파이썬] AI 활용 웹 서비스 개발 기록 : 5 models_dir 설명이전 내용 [파이썬] AI 활용 웹 서비스 개발 기록 : 4 frontend 설명이전
puppy-foot-it.tistory.com