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)"을 이용한 모델링이다.
특히, 객체 지향 프로그래밍의 상속 개념을 데이터베이스에 적용한 것으로 볼 수 있다고한다.
Single Table Inheritance: 단일 테이블 상속 - 모든 데이터를 하나의 테이블에 저장.
Class Table Inheritance: 클래스 테이블 상속 또는 다중 테이블 상속 - 슈퍼클래스와 서브클래스의 속성을 별도의 테이블에 저장하고 1:1 관계로 연결.
Concrete Table Inheritance: 구체 테이블 상속 - 각 서브클래스가 자체 테이블을 가지며, 슈퍼클래스의 속성을 포함. (슈퍼클래스 존재 X)
Multi Table Inheritance: 다중 테이블 상속 - 테이블 간의 PK가 다른 경우.
이러한 개념을 포함하여 일반적으로 "데이터베이스 상속 모델링(Database Inheritance Modeling)"이라고 부를 수 있다고함. 보통 ORM에서 자주 사용.
이러한 개념들은 마틴파울러의 책 Martin Fowler's book Patterns of Enterprise Application Architecture. 에서 나왔다고한다.
MTI 데이터베이스모델링에 대한 예제 - 완전히 MTIㄹ르 따라는건 아닌것 같음
DB 모델링에 대한 피드백
숨고, 알바천국, 당근마켓 같은 서비스는 기본적으로 서비스 수요층이고 특정 유저들만 공급자이다 -> 만약에 이런 서비스라면
user+patient
테이블을 합쳐서 하나로 관리하고 컨텐츠 제공자들은 아예 다른 테이블staff
로 빼두어 관리하는 것도 하나의 방법이고.. 사실 가장 많이 들었던 피드백이다. 굳이 user 테이블을 나누는이유?! 😭 납득시키기가 힘들었다대부분의~ 서비스들
이라고는 말할 수 없지는 업무상에서는 위의 처럼 데이터베이스 상속개념을 많이 사용하지 않는 것 같다