FastAPI 프로젝트에 서비스 씌우기 - DB 모델링

회원가입, 로그인, 게시판 기능이 있는 어플리케이션을 FastAPI으로 만드는데 조금 더 복잡한(?) 유저 테이블을 구현해보고 싶었습니다.

이 중 회원관련된 테이블을 모델링하는데 단순한 user 테이블로 작성하기 싫어서 user테이블, 그리고 이를 개념적으로 상속받는 patient환자 테이블과 hospitalstaff테이블 모델링하는 과정에 대해 작성해보았습니다.

서비스 개요

  • 기술스택 : fastAPI, mysql, mongodb, redis

  • 서비스명 : 차칸의사

  • 제공서비스

    • 성예사가 모티브

    • 환자끼리 수술에 대해 이야기 할 수 있는 게시판이 존재한다. 환자는 병원을 북마크를 할 수 있다. 병원스태프는 내 담당병원을 좋아요 한 환자들을 모아서 볼 수 있다

      • 회원게시판 CRUD

      • 가입하면 기본적으로 patient가된다

      • 병원측계정은 회원가입이 필요없다. (이미 DB에 관리자가 등록해놨다고 가정)

      • 환자들은 회원게시판 CRUD 가능하지만 병원관계자들은 회원게시판을 읽기만 할 수 있다.

모델링

회원관련 테이블들

  • 총 3개의 테이블(user, patient, hostpitalstaff)가 존재한다. 슈퍼어드민계정들은 별도의 테이블에서 관리.

  • 사용자는 병원관계자 또는 환자가 될 수 있다. 동시에 둘 다 될 수 없다. 즉 user와 환자는 1:1 관게이고 마찬가지로 user와 병원관게자도 1:1 이다

  • 모든 병원관계자는 사용자이다

  • 모든 환자는 사용자이다

  • 병원관계자는 환자가 될 수 없다

  • 환자는 병원관계자가 될 수 없다

  • 환자가 성형에 대해 이야기하는데 병원관계자가 그 게시판에 글을 작성하는것 자체가 홍보가 될 수 있으므로 이를 방지한다.

  • 기존에 이미 환자였던 사람이 병원관계자로 역할이 바뀌게 되면 기존에 있던 글은 삭제되지는 않지만 미노출된다. patient 테이블에 있는 정보는 변하지 않고 그대로 존재한다. 단 이미 병원관계자와 환자가 역할 분리가 되어있지만 이러한 경우가 생길 수 있으므로 이떄는 유저테이블에 role(intenum)을 부여한다. 환자가 병원관계자가 되면 이 번호가 바뀐다.

  • 하나의 테이블에 병원관계자+환자를 넣으면 안된다. 만약에 병원관계자+환자의 정보를 한테이블에 두개된다면 single table inheritance

    • 환자 정보에는 혈액형등이 들어가는데 병원관계자는 해당 컬럼을 사용하지 않으니 환자의 추가 정보를 user에 넣는거는 비효율적이다. 따라서 user와 patient테이블은 분리되어야한다

    • 병원관계자에게는 병원정보와 직책에 대한 정보가 들어가므로 user와 병원관계자 테이블은 부리되어야한다

    • 이때 병원관계자와 환자는 user테이블과 연결성이 생기는데 이 연결성을 어떻게 표현할 것인가? user와 병원관계자 그리고 user와 환자는 모두 1:1 관계를 가지므로 class table inheritance구조를 따라가자

      • 만약에 병원관계자의 pk != 유저 테이블 pk라면? -> multi table inheritance

      • 만약에 병원관계자의 pk == 유저 테이블 pk라면? -> class table inheritance

+--------------+       +--------------+       +------------------+
|   patient    |       |  users       |       |  medical_staff   |
+--------------+       +--------------+       +------------------+
| userid(PK,FK)|<----->| userid (PK)  | <--->| user_id (PK,FK)   |
| blood_type   |       | username     |       | hospital_info    |
| ...          |       | password     |       | dept.            |
|  ...         |       | role (Enum)  |       |  .....           |              +--------------+       | ...              |
+--------------+       +--------------+       +------------------+

만약에 환자와 병원관계자 테이블의 공통사항(아이디, 이메일, 비밀번호)등을 user테이블에 넣지않고 각 테이블에 그대로 중복되게 만들어 구현한다면 그건 concreate table inheritance를 구현한것

서비스 관련 테이블들

  • patient는 board에 글을 남길 수 있다 - board 테이블

  • hospitalstaff는 hospital을 수정 할 수 있다 - hospital 테이블 (마지막 수정자 컬럼필요)

  • patient는 board를 좋아요 할 수 있다 boardLike 테이블

  • patient는 hospital을 좋아요 할 수 있다 hospitalLike 테이블


DB 계층 상속이란?

뭘 만들고 싶은지보다 어떤 디비 모델링을 가져갈까 생각을 많이했었다(사유: 복잡한 쿼리 사용해보고 싶어서 for 실험 - -) 하지만 정작 모델링을 해보니 내가 뭘하고 싶은지가 명확하지 않으면 디비 모델링에 의미가 없단걸 깨달았다. 왜 이렇게 모델링했어요? 라고 하면 그냥요 라고 말하는것도 어이없고, 내가 서비스에서 뭘 만들고, 어떤 회원에게 어떤 권한을 줄지를 생각하고 해야 조금 더 의미있는 고민을 하게 된다는걸 깨달았다.

여튼 이번에 가장 많이 참고한건 "계층 상속(Inheritance)"을 이용한 모델링이다.

특히, 객체 지향 프로그래밍의 상속 개념을 데이터베이스에 적용한 것으로 볼 수 있다고한다.

  1. Single Table Inheritance: 단일 테이블 상속 - 모든 데이터를 하나의 테이블에 저장.

  2. Class Table Inheritance: 클래스 테이블 상속 또는 다중 테이블 상속 - 슈퍼클래스와 서브클래스의 속성을 별도의 테이블에 저장하고 1:1 관계로 연결.

  3. Concrete Table Inheritance: 구체 테이블 상속 - 각 서브클래스가 자체 테이블을 가지며, 슈퍼클래스의 속성을 포함. (슈퍼클래스 존재 X)

  4. Multi Table Inheritance: 다중 테이블 상속 - 테이블 간의 PK가 다른 경우.

이러한 개념을 포함하여 일반적으로 "데이터베이스 상속 모델링(Database Inheritance Modeling)"이라고 부를 수 있다고함. 보통 ORM에서 자주 사용.

이러한 개념들은 마틴파울러의 책 Martin Fowler's book Patterns of Enterprise Application Architecture. 에서 나왔다고한다.


DB 모델링에 대한 피드백

  • 숨고, 알바천국, 당근마켓 같은 서비스는 기본적으로 서비스 수요층이고 특정 유저들만 공급자이다 -> 만약에 이런 서비스라면 user+patient 테이블을 합쳐서 하나로 관리하고 컨텐츠 제공자들은 아예 다른 테이블 staff 로 빼두어 관리하는 것도 하나의 방법이고.. 사실 가장 많이 들었던 피드백이다. 굳이 user 테이블을 나누는이유?! 😭 납득시키기가 힘들었다

  • 대부분의~ 서비스들 이라고는 말할 수 없지는 업무상에서는 위의 처럼 데이터베이스 상속개념을 많이 사용하지 않는 것 같다