Skip to main content

M사 척추/골반 지표 계산 프로그램

X-Ray 사진을 스마트폰 카메라로 촬영하여 AI를 통해 뼈 위치를 찾고 척추/골반 관련 지표를 계산해주는 프로그램입니다. 시스템 설계부터 백엔드, 인프라까지 담당했던 프로젝트입니다. 미국에서 사용할 프로그램이었기에 환자 개인 정보가 자의든 타의든 간에 수집될 경우 관련 법안이 너무 엄격하여 이를 피하기 위해 어떠한 개인 정보도 프로그램에 들어가선 안되었습니다. 이것 때문에 설계를 하면서 많은 고충이 있었던 프로젝트 였습니다.

📝개요

  • 목적: 기존에도 척추/골반 지표를 계산해주는 프로그램이 있었으나 수술실에서는 사용이 불가능하여 수술실에서 즉각적으로 해당 지표를 계산해주는 서비스 제공
  • 주요 기능: 계정/권한 관리, 사용 히스토리 조회, 통계 조회, 사진 태깅, 감사 로그, 투시 왜곡 보정(Front), 좌표 추정 및 계산(Front)
  • 담당 역할: 팀장, Backend 개발
  • 기간: 2025.01 ~ 2025.02, 2025.10 ~ 2025.11

🛠️기술스택

  • Backend: FastAPI (ASGI)
  • Auth: OAuth2, Email
  • DB: SQLModel + AsyncSession, Alembic, MySQL
  • Storage: AWS S3
  • Image/AI Model Serving: AWS CloudFront
  • Image Overlay: OpenCV, Pillow
  • Image Masking: AWS Textract
  • Audit Logging: AWS CloudWatch
  • Packaging/Deploy: Poetry, Docker, AWS ECS
  • Linting: Black, Isort, Ruff

🏗️아키텍처

System Design

Service Flow

  • 인증

💡핵심 기여

  • 프로젝트 설계
    • 인증
      • 프로젝트 초기에는 Cognito를 사용하였으나 고객사의 요청으로 백엔드 서버에서 직접 관리하는 것으로 변경
        • Cognito 사용 시 OAuth2의 Authorization Code Flow가 강제되어 App에서도 Safari가 열려 사용자에게 권한 요청을 하게 됨
        • 고객사 측에서 권한 요청 화면이 안 뜨게 하는 것을 요청
      • Apple, Google, Email 로그인(관리자, 테스트용) 구현
      • Web에서는 OAuth2 Authorization Code Flow를 사용하고 App에서는 Implicit Flow를 사용
    • AI Model 사용
      • 사용하는 AI 모델은 총 2가지로 사진 좌표, 뼈 좌표 추정 모델임
      • 사용 방식은 Client에서 직접 구동하는 것으로 결정
        • 모델이 작아 모바일에서도 충분히 동작할 것으로 판단 되었음
        • 카메라에서 사진 좌표를 실시간으로 보여주는 것이 UX적으로 더 나을 것이라 판단 되었음
      • Model Serving은 App은 앱 번들에 포함 시키고 Web은 CloudFront를 통해 다운받는 것으로 결정
    • 감사 로그
      • 로그를 수정할 수 없는 CloudWatch를 사용하기로 결정
    • 태깅
      • Client에서 태그 DB를 관리하고 AWS KMS를 통해 DB 파일을 암호화 해서 S3에 업로드 하는 방식 사용
        • 태그에 의사들이 개인정보를 넣을 가능성이 있어 Backend DB에 암호화를 하더라도 넣지 말아달라는 고객사 요청이 있었음
        • App과 Web을 모두 사용하기 때문에 동일 사용자의 여러 기기 간에 태그를 공유해야한다는 요구사항이 있었음
  • Backend 전반 개발
    • 이미지에 있는 Text 마스킹
      • 사용자가 촬영한 X-Ray 사진에 개인정보가 있을 수 있어 이미지에 있는 모든 텍스트를 AWS Textract로 OCR을 수행한 후 개인정보를 마스킹해서 저장
    • 좌표, 수치 등을 오버레이한 이미지 생성
      • 과거 사진 다운로드 시 App에서 수행했던 것과 비슷한 경험을 제공하기 위해 DB에 저장된 값을 기반으로 원본 이미지에 오버레이를 생성
      • Backend에서 처리한 이유
        • 스크린 캡처는 이미지의 해상도가 낮아져 고객사에서 거부함
        • 원본 해상도를 유지하기 위해서는 이미지 위에 직접 그려야 했음
        • 좌표 수정이 가능했기에 Front에서 처리할 경우 매번 이미지를 생성하고 업로드를 해야했기에 매우 비효율적이라 판단함
          • 사용자가 임의로 강제 종료하는 상황까지 고려해야 했기에 Front에서는 수정한 수치만 전달하는 것으로 결정함
      • OpenCV, Pillow를 사용하여 오버레이 된 이미지 생성
        • Pillow는 느리지만 폰트 적용을 위해 사용
    • Front Code Generator 이슈 해결
      • Front에서는 FastAPI에서 자동으로 생성한 openapi.json을 기반으로 코드 생성기를 사용 중
      • 히스토리 검색 API의 경우 FastAPI Filter 라이브러리를 사용했는데 해당 라이브러리를 사용할 경우 GET Query에 Optional을 반드시 사용해야 해서 openapi.json에 anyOf로 들어갔음
      • 이 경우 코드 생성기에서 null 값이 아니라 빈 문자열을 넣어 주게 되어있어 의도하지 않은 일이 발생함
      • 일반적인 경우 비 필수 파라미터의 경우 pram:type = Query(None)으로 정의해도 json에서 "required": false로 들어갔기에 문제가 없었음
      • FastAPI의 Depends, FastAPI Filter의 FilterDepends 코드를 분석하여 FilterDepends를 오버라이드 하는 방식으로 문제 해결
  • Frontend 개발
    • App의 소셜 로그인, 약관 동의, 히스토리, 설정 화면 개발
  • DNS 등 AWS 인프라 설정
    • Route53을 통한 도메인 연결
    • SSL 인증서 발급 및 연결