본문 바로가기
Back-end/기초부터 따라하는 nest.js

시즌 2 #5. 기초부터 따라하는 Nest.js 2 : Nest.js 프로젝트 DB 구조 설명

by hsloth 2024. 5. 18.

지난 시간에는 Nest.js의 구조에 대해서 알아봤습니다.

https://suloth.tistory.com/199

 

시즌 2 #4. 기초부터 따라하는 Nest.js 2 : 이제 Nest.js를 배워봅시다!

지난 시간에는 Express와 MySQL을 연동하는 방법을 알아보고, 간단하게 회원가입 API를 구현했습니다.https://suloth.tistory.com/198 시즌 2 #3. 기초부터 따라하는 Nest.js 2 : Express 배우기(2)지난 시간에는 간

suloth.tistory.com

 

이번 시간에는 Nest.js 프로젝트를 생성해보고 간단하게 API를 만들어 보도록 하겠습니다.


과제 정답...은 아니고 제가 짠 테이블 구조입니다.


 

간단하게 짜봤습니다.

 

https://www.erdcloud.com/

 

ERDCloud

Draw ERD with your team members. All states are shared in real time. And it's FREE. Database modeling tool.

www.erdcloud.com

 

저는 위 사이트르 참고해서 테이블 구조를 그렸습니다.

MySQL Workbench나 UML도구를 이용해서 그려도 됩니다.


User Table


그러면 간단하게 테이블 구조를 한 번 보겠습니다. 먼저, User 테이블입니다.

PK의 경우 INT 타입의 id속성을 따로 만들어서 AUTO_INCREMENT 되는 대체키(surrogate key입니다. Alternative key 아닙니다)를 설정해주었습니다. "Email이 Unique한 값이라서 PK로 설정하면 안되나요?" 라고 생각하시는 분들도 계실 수 있을 것 같은데, PK는 기본적으로 Uniqueness(유일성), Stability(안정성. 수정되면 안됨), Irreducibility(비환원성. 더이상 쪼갤 수 없음), Simplicity(단순성. 기억하기 쉽고 시스템과 호환성이 좋아야함-메모리, 용량 등)을 만족해야합니다. 그 점에서 email은 수정이 가능하므로 Stability에 위반되기 때문에 적절하지는 않다고 생각했습니다. (email을 정책적으로 수정불가능하게 만들었다고 하더라도 비즈니스적인 입장에서 "영원히 변동되지 않는다"라는 보장은 없기 때문)

추가적으로 사용자 식별(로그인)을 위해 필요한 email과 password는 VARCHAR타입으로 설정해주었고, nickname 또한 VARCHAR로 설정하였습니다.

그리고 중요한건데, DB에 존재하는 모든 데이터들은 언제, 어디서, 어떤식으로 활용될지 모르므로 기본적으로 createdAt, updatedAt, deletedAt 칼럼을 두어 생성 날짜, 수정 날짜, 삭제 날짜를 기록해둡니다. (꼭 그렇다는 건 아닙니다)

 

DeletedAt 칼럼에 대한 토막 상식

더보기

DeletedAt 칼럼은 Soft Delete를 위한 칼럼입니다.

Soft Delete란?

논리 삭제라는 뜻으로 실제로 데이터를 DB에서 삭제하는 Hard Delete와 반대되는 말입니다.

deletedAt(Date), isDeleted(Boolean) 등의 칼럼을 사용해서 구현할 수 있으며, 실제로 DB에서 데이터를 삭제하는 것이 아닌, 데이터가 삭제된 것처럼 동작하게끔 만들어주는 것을 말합니다.

예를들어 댓글 목록을 불러올 때, 삭제한 댓글은 불러오고 싶지 않다면 deletedAt이 null인 댓글들만 불러오는 방법을 이용해서 논리 삭제된 댓글들은 불러오지 않도록 합니다. (논리 삭제가 되었다면, deletedAt에 삭제된 날짜가 담기니까요)

 

그렇다면 Soft Delete는 왜 사용하는걸까?

이유는 다양합니다. 첫 번째로 위에서 언급햇듯이, 데이터를 복구/활용하기 위해서입니다. 갑자기 해당 데이터가 필요해지는 상황이 생길수도 있고, 이러한 데이터들을 통해서 통계를 낸다던가 하는 상황이 있으면 데이터가 많으면 많을수록 좋으니까요. 또한 범죄에 연루되거나 할 경우 관련된 데이터를 참고해야하는데, 데이터를 직접적으로 지워버리면 난감한 상황이 벌어질 수도 있습니다. 이런 경우에는 해당 데이터를 복구하여 증거를 남겨놓을 수 있도록 해놔야겠죠.

두 번째는 정책때문입니다. 저도 자세히까지는 알지 못하지만, 법적으로 특정 데이터의 경우는 보관 기간이 정해져 있다고 알고 있습니다. 예를들어 결제와 관련된 기록은 5년간 보관해야하는 것으로 알고 있습니다.

 

단점

1. 서버 로직이 복잡해진다는 단점이 있습니다. deletedAt이라는 칼럼에 대한 분기처리를 따로 해주어야 하므로 로직이 복잡해질 수 있습니다.

2. 실제 데이터를 삭제하는 것이 아니기 때문에 데이터 베이스의 용량은 줄어들지 않는다는 단점이 있습니다. 오히려 논리 삭제를 위한 추가적인 칼럼때문에 차지하는 용량이 늘어나죠.


Post Table


Post 테이블도 간단하게 작성해봤습니다.

 

PK인 Auto increment의 INT id를 두었고, 게시글을 작성하는데 필요한 title, content 그리고 누가 작성했는지에 대한 정보도 필요하니, userId를 FK(외래키)로 걸어주었습니다.

또한 여기도 마찬가지로 날짜에 관련된 칼럼들을 설정해주었습니다.

 

이건 다른 이야기인데 여기서 하나 팁(?)을 드리자면, 게시글 내용의 경우 보통 글자 크기나 글자 색을 바꾸거나 이미지를 첨부하거나 하는 등의 일을 할 수 있는데 게시글 내용의 글자들 뿐만 아니라, 그런 스타일이나 이미지들까지 내용으로 저장하려면 html의 body태그를 한꺼번에 저장하는 것도 방법입니다.


Comment Table


Comment 테이블입니다. 댓글의 경우 대댓글까지 고려해서 구조를 설계했습니다.

 

요즘 웬만한 댓글들은 다 대댓글(혹은 답글) 기능이 있죠? 대댓글 기능을 위해 부모 댓글에 대한 정보를 가지는 parentId 칼럼을 두었습니다. 이렇게 되면 대대댓글도 가능하고 대대대댓글도 가능하기 때문에, 따로 서버에서 depth를 조정할 수 있도록 처리를 해주거나 하는 등의 방법으로 댓글의 depth를 제한할 수 있습니다. 저희는 대댓글까지만 가능하도록 할 예정입니다.

그리고 댓글에는 내용이 있고, 어떤 유저가 쓴 댓글인지와 어떤 게시글에 남긴 댓글인지에 대한 정보가 필요하므로 각각 content, userId, postId 칼럼을 두었습니다.

 

참고로, 대댓글을 구현하기 위한 테이블 설계 방법은 위의 방법한 있는 것이 아닙니다. ParentComment와 ChildComment를 매핑하는 관계 테이블을 둔다던가, 댓글 테이블과 대댓글 테이블을 나눠서 둔다던가 하는 등의 방법을 사용해도 좋습니다. 설계에 정답은 없으니, 자신이 생각하기에 좋은 방법인 것 같으면 그 설계를 따라가면 됩니다. 그러다가 장애를 마주치면 해결하는 과정을 글로 적어보는 것도 좋을 것 같습니다 ㅎㅎ