Files
cloud-sharp-docs/설계/db/설계.md
2026-03-18 17:53:41 +09:00

12 KiB

Cloud# — 데이터베이스 설계서

1. 엔티티 목록

엔티티 설명
User 사용자 인증 정보 및 스토리지 한도 관리
Folder 사용자별 폴더 트리 구조 표현
FileItem 파일 메타데이터 및 저장소 객체 연결
UploadSession tus 기반 업로드 진행 상태 추적

2. ER 다이어그램

!개념적설계_erd.svg


3. 엔티티 상세 설계


3.1 User

사용자의 인증 정보와 스토리지 한도를 관리하는 엔티티.

주요 역할

  • 로그인 식별자 관리
  • 권한(role) 관리
  • 전체 사용 가능 용량 / 사용 중 용량 관리

컬럼 정의

컬럼명 타입 Null 설명
id UUID / BIGINT NOT NULL PK — 내부 식별자
email VARCHAR NOT NULL 로그인 식별자. UNIQUE
password_hash VARCHAR NOT NULL 해시된 비밀번호
display_name VARCHAR NULL 표시 이름
role ENUM NOT NULL ADMIN | USER
storage_allowed_bytes BIGINT NULL 허용 용량. NULL 이면 무제한
storage_used_bytes BIGINT NOT NULL 현재 사용 중 용량. 기본값 0
created_at TIMESTAMP NOT NULL 계정 생성 일시
updated_at TIMESTAMP NOT NULL 마지막 수정 일시
deleted_at TIMESTAMP NULL 소프트 삭제 일시

설계 포인트

  • emailUNIQUE 제약으로 중복 가입 방지
  • storage_allowed_bytesNULL 이면 무제한 처리
    • 애플리케이션 레이어에서 NULL 여부를 먼저 확인
  • storage_used_bytes집계 캐시 컬럼으로 운영
    • 즉시 조회 성능은 우수하나, 파일 업로드·삭제 시 반드시 동기화 필요
    • 정합성 보장을 위해 트랜잭션 내에서 함께 갱신

3.2 Folder

사용자별 폴더 트리를 표현하는 엔티티.

주요 역할

  • 폴더 계층 구조 표현
  • 탐색기 경로 구성
  • 파일의 논리적 위치 제공

컬럼 정의

컬럼명 타입 Null 설명
id UUID / BIGINT NOT NULL PK
owner_user_id FK → User NOT NULL 소유 사용자
parent_folder_id FK → Folder NULL 부모 폴더. NULL 이면 루트 폴더
name VARCHAR NOT NULL 폴더 이름 (부모 기준 상대명)
full_path VARCHAR NULL 전체 경로 캐시 (예: /문서/프로젝트/2025)
created_at TIMESTAMP NOT NULL 생성 일시
updated_at TIMESTAMP NOT NULL 수정 일시
deleted_at TIMESTAMP NULL 소프트 삭제 일시

설계 포인트

자기참조 트리 구조

parent_folder_id IS NULL  →  루트 폴더
parent_folder_id = X      →  X 폴더의 하위 폴더

full_path 컬럼의 위치

full_path 는 원본 진실(source of truth)이 아닌 조회 최적화용 캐시 컬럼이다.

구분 컬럼 역할
원본 진실 id, parent_folder_id, name 실제 구조의 기준
캐시 full_path 목록 조회·검색·WebDAV 경로 변환·breadcrumb 표시용
  • 폴더 이름 변경·이동 시 full_path 와 하위 폴더의 full_path함께 갱신해야 함
  • 불일치 발생 시 id / parent_folder_id 기준으로 재계산 가능

유니크 제약

같은 부모 폴더 아래에서 동일한 이름의 폴더는 허용하지 않는다.

UNIQUE (owner_user_id, parent_folder_id, name)  -- 활성 데이터 기준
  • 소프트 삭제 구현 시 deleted_at IS NULL 조건부 유니크 인덱스 권장

루트 폴더 정책

  • 사용자당 루트 폴더(parent_folder_id IS NULL) 는 1개 권장
  • 애플리케이션 레이어 또는 DB 제약으로 강제

3.3 FileItem

사용자 관점에서 보이는 파일 자체의 메타데이터를 관리하는 엔티티.

주요 역할

  • 탐색기 파일 목록 조회
  • 파일명, MIME, 크기, 미리보기 상태 관리
  • 실제 저장소(LocalFS / S3)의 객체와 연결

컬럼 정의

컬럼명 타입 Null 설명
id UUID / BIGINT NOT NULL PK
owner_user_id FK → User NOT NULL 소유 사용자
folder_id FK → Folder NOT NULL 소속 폴더
display_name VARCHAR NOT NULL 사용자에게 보이는 파일 이름
storage_key VARCHAR NOT NULL 실제 저장소 객체 키. UNIQUE
size_bytes BIGINT NOT NULL 파일 크기 (>= 0)
mime_type VARCHAR NULL MIME 타입 (예: image/jpeg)
checksum_sha256 VARCHAR NULL 무결성 검증용 해시
preview_status ENUM NOT NULL 미리보기 파이프라인 상태
metadata_json JSON / TEXT NULL 파일 종류별 가변 메타데이터
created_at TIMESTAMP NOT NULL 업로드 완료 일시
updated_at TIMESTAMP NOT NULL 수정 일시
deleted_at TIMESTAMP NULL 소프트 삭제 일시

설계 포인트

storage_keydisplay_name 분리

display_name : 사용자에게 보이는 이름  →  "보고서 최종.pdf"
storage_key  : 저장소의 실제 키        →  "user/12/ab/cd/f83e...uuid.bin"
  • 파일 이름 변경 시 display_name 만 변경하고 저장소 객체는 그대로 유지
  • storage_key 가 외부에 노출되지 않도록 주의

metadata_json 활용 예시

// 이미지
{ "width": 1920, "height": 1080 }

// 비디오
{ "duration": 3600, "codec": "h264", "bitrate": 4000 }

// 문서
{ "page_count": 42 }

preview_status 상태 흐름

PENDING → PROCESSING → DONE
                     → FAILED
         (미지원 포맷) → UNSUPPORTED

파일명 중복 정책

같은 폴더 내에서 동일한 파일 이름은 허용하지 않는다.

UNIQUE (owner_user_id, folder_id, display_name)  -- 활성 데이터 기준
  • 소프트 삭제 구현 시 deleted_at IS NULL 조건부 유니크 인덱스 권장

3.4 UploadSession

tus 기반 대용량 업로드의 진행 상태를 관리하는 엔티티.

주요 역할

  • 업로드 시작 ~ 완료까지의 진행 상태 추적
  • 실패·중단·재개 처리
  • 임시 저장 위치와 최종 FileItem 생성 연결

컬럼 정의

컬럼명 타입 Null 설명
id UUID / BIGINT NOT NULL PK
owner_user_id FK → User NOT NULL 업로드 요청 사용자
target_folder_id FK → Folder NOT NULL 완료 후 파일이 위치할 폴더
token VARCHAR NOT NULL 외부 공개용 식별자. UNIQUE
tus_upload_id VARCHAR NULL tus 서버와의 매핑 ID. UNIQUE 가능
status ENUM NOT NULL 업로드 상태 (아래 상태 흐름 참고)
expected_size BIGINT NOT NULL 전체 파일 크기 (bytes)
received_size BIGINT NOT NULL 현재까지 수신된 크기 (bytes)
original_name VARCHAR NOT NULL 업로드 원본 파일명
mime_type VARCHAR NULL MIME 타입
storage_key_temp VARCHAR NULL 임시 저장 경로
file_item_id FK → FileItem NULL 완료 후 생성된 FileItem 참조
created_at TIMESTAMP NOT NULL 업로드 세션 생성 일시
expires_at TIMESTAMP NULL 세션 만료 일시
completed_at TIMESTAMP NULL 업로드 완료 일시

설계 포인트

token 과 내부 id 분리

id     : 내부 DB 식별자  →  외부 노출 금지
token  : 클라이언트가 업로드 재개 시 사용하는 공개 식별자

status 상태 흐름

CREATED → UPLOADING → COMPLETED
                    → FAILED
        → CANCELLED
        → EXPIRED

업로드 완료 처리 흐름

업로드 완료 시 아래 세 작업을 하나의 트랜잭션으로 처리한다.

1. UploadSession.status  →  COMPLETED
2. FileItem 신규 생성
3. User.storage_used_bytes  +=  size_bytes

received_size 제약

received_size <= expected_size  -- 항상 유지

4. 관계 정의

관계 카디널리티 설명
UserFolder 1 : N 한 사용자는 여러 폴더를 소유
FolderFolder 1 : N 폴더는 하위 폴더를 가짐 (자기참조)
UserFileItem 1 : N 한 사용자는 여러 파일을 소유
FolderFileItem 1 : N 한 폴더는 여러 파일을 포함
UserUploadSession 1 : N 한 사용자는 여러 업로드 세션을 가짐
FolderUploadSession 1 : N 한 폴더는 여러 업로드 세션의 목적지가 됨
UploadSessionFileItem 1 : 0..1 완료된 세션은 하나의 FileItem을 생성

5. 제약 조건 요약

User

제약 내용
PK id
UNIQUE email
CHECK storage_used_bytes >= 0

Folder

제약 내용
PK id
FK owner_user_idUser.id NOT NULL
FK parent_folder_idFolder.id NULL 허용
UNIQUE (owner_user_id, parent_folder_id, name) — 활성 데이터 기준
정책 사용자당 루트 폴더(parent_folder_id IS NULL) 1개 권장

FileItem

제약 내용
PK id
FK owner_user_idUser.id NOT NULL
FK folder_idFolder.id NOT NULL
UNIQUE storage_key
UNIQUE (owner_user_id, folder_id, display_name) — 활성 데이터 기준
CHECK size_bytes >= 0

UploadSession

제약 내용
PK id
FK owner_user_idUser.id NOT NULL
FK target_folder_idFolder.id NOT NULL
FK file_item_idFileItem.id NULL 허용
UNIQUE token
UNIQUE tus_upload_id (NULL 제외)
CHECK received_size <= expected_size
CHECK expected_size >= 0

6. 설계 결정 사항 (Decision Log)

# 결정 사항 이유
1 storage_used_bytes 를 집계 캐시 컬럼으로 관리 매 조회 시 SUM 집계 대신 즉시 응답. 대신 업로드·삭제 트랜잭션에서 동기화 필수
2 full_path 를 캐시 컬럼으로 정의 폴더 이동·이름 변경 시 하위 경로 전체 갱신이 필요하지만, 조회·WebDAV·breadcrumb 성능 확보
3 storage_keydisplay_name 분리 파일 이름 변경이 저장소 객체 이동 없이 메타데이터 변경만으로 처리 가능
4 UploadSession 완료 처리를 단일 트랜잭션으로 FileItem 생성과 storage_used_bytes 증가의 정합성 보장
5 소프트 삭제 (deleted_at) 적용 실수 복구, 휴지통 기능 지원. 유니크 제약은 deleted_at IS NULL 조건부 인덱스로 처리
6 token (외부) / id (내부) 식별자 분리 내부 PK 노출 방지. 클라이언트는 token 으로만 업로드 세션 접근