From 52aebed5d7fc47026bded2667be1f30638cd069a Mon Sep 17 00:00:00 2001 From: son Date: Mon, 16 Mar 2026 16:17:17 +0900 Subject: [PATCH] first --- .gitignore | 26 + 기획/기획서.md | 963 ++++++++++++++++++++++++++++++++++++ 기획/제안서.md | 369 ++++++++++++++ 설계/db/개념적 설계.md | 351 +++++++++++++ 설계/img/개념적설계_erd.svg | 102 ++++ 설계/기능요구사항.md | 33 ++ 설계/무제.md | 0 7 files changed, 1844 insertions(+) create mode 100644 .gitignore create mode 100644 기획/기획서.md create mode 100644 기획/제안서.md create mode 100644 설계/db/개념적 설계.md create mode 100644 설계/img/개념적설계_erd.svg create mode 100644 설계/기능요구사항.md create mode 100644 설계/무제.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52f93dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# OS junk +.DS_Store +Thumbs.db +desktop.ini + +# Editor temp files +*.swp +*.swo +*~ + +# IDE settings +.vscode/ +.idea/ + +# Ignore all Obsidian settings +.obsidian/* + +# But keep selected customization files +!.obsidian/snippets/ +!.obsidian/snippets/** +!.obsidian/themes/ +!.obsidian/themes/** + +.trash/ +*.tmp +*.bak diff --git a/기획/기획서.md b/기획/기획서.md new file mode 100644 index 0000000..1f326a6 --- /dev/null +++ b/기획/기획서.md @@ -0,0 +1,963 @@ + +> 버전: v0.1 +> 목적: MVP 개발 범위 확정 및 구현 기준 문서 +> 저장소 전략(1차): **Local FS** (향후 S3/MinIO로 확장 가능하도록 추상화) + +--- + +## 1) 문서 목적 + +- MVP 범위 확정 + +- 기능 우선순위 정의 + +- 도메인 모델/데이터 구조 초안 정리 + +- API/업로드/다운로드/공유 흐름 정의 + +- 구현 시 의사결정 기준(로컬FS, tus, 미리보기, 보안) 명시 + + +--- + +## 2) 제품 정의 (개발 관점 요약) + +### 목표 + +Nextcloud의 핵심 기능(파일 관리/공유/미리보기)을 제공하되, **더 빠른 체감 UX**를 목표로 하는 파일 호스팅 서비스의 MVP 구현. + +### 핵심 전략 + +- **UI/응답 체감 속도 최적화** + +- **대용량 업로드 안정성 확보 (tus)** + +- **저장소는 로컬FS로 단순 시작** + +- **메타데이터(DB)와 파일 저장(Local FS) 분리** + +- **향후 S3/Object Storage 전환 가능한 구조** + + +--- + +## 3) 개발 범위 (MVP 범위 확정) + +## 3-1. 포함 범위 (In Scope) + +### A. 인증/회원 + +- 회원가입 + +- 로그인 / 로그아웃 + +- 인증 세션 유지 (Cookie 또는 JWT) + +- 기본 프로필 조회 + + +### B. 파일/폴더 관리 + +- 폴더 생성 + +- 폴더명 변경 + +- 폴더 삭제 (비어있지 않은 경우 정책 정의) + +- 파일 업로드 (tus 기반) + +- 파일 다운로드 + +- 파일명 변경 + +- 파일 이동 (폴더 이동) + +- 파일 삭제 + +- 파일 목록 조회 (폴더 단위) + +- 정렬 (이름/크기/수정일) + + +### C. 공유 + +- 공유 링크 생성 + +- 링크 만료일 설정(선택) + +- 링크 비밀번호 설정(선택) + +- 공유 링크 비활성화 + +- 공유 링크를 통한 다운로드 + + +### D. 미리보기 (MVP 최소) + +- 이미지 (jpg/png/webp/gif) + +- 텍스트 (txt/md/json/log 등) + +- PDF (브라우저 내장 뷰어 활용) + +- (선택) 동영상 기본 재생은 MVP 후순위 + + +### E. 운영 기본 + +- 사용자별 저장 용량 집계(Quota 표시) + +- 업로드 크기 제한 + +- 기본 로그(업로드/삭제/공유 생성) + + +--- + +## 3-2. 제외 범위 (Out of Scope, MVP) + +> “나중에 넣을 기능”으로 명시 + +- WebDAV + +- FTP/SFTP + +- 파일 버전 관리 + +- 중복 파일 탐지 + +- 실시간 협업 편집 + +- 커뮤니티/채팅/공유 스페이스 + +- 서버 측 외부 다운로드(유튜브/토렌트 등) + +- 관리자 대시보드 고도화 + +- 바이러스 스캔 (후속 가능) + + +--- + +## 4) 핵심 요구사항 (FR: Functional Requirements) + +아래는 개발/테스트 가능한 형태로 쪼갠 기능 요구사항이다. + +### FR-001 회원가입 + +- 이메일/아이디 + 비밀번호로 회원가입 가능 + +- 중복 계정 방지 + +- 비밀번호 해시 저장 + + +### FR-002 로그인/로그아웃 + +- 유효한 자격 증명으로 로그인 가능 + +- 로그인 후 보호 API 접근 가능 + +- 로그아웃 시 세션/토큰 무효화 처리 + + +### FR-003 루트 폴더 접근 + +- 로그인한 사용자는 자신의 루트 폴더를 조회할 수 있어야 함 + +- 최초 가입 시 사용자 루트 공간 자동 생성 + + +### FR-004 폴더 생성 + +- 특정 폴더 하위에 새 폴더 생성 가능 + +- 동일 부모 내 중복 이름 정책 정의 (허용/비허용 중 선택) + + +### FR-005 파일 업로드 (tus) + +- 대용량 파일 업로드 가능 + +- 네트워크 중단 후 재개 가능 + +- 업로드 완료 후 메타데이터 저장 및 목록 반영 + + +### FR-006 파일 다운로드 + +- 권한 있는 사용자는 파일 다운로드 가능 + +- 공유 링크로도 다운로드 가능 (권한/만료 조건 충족 시) + + +### FR-007 파일/폴더 이름 변경 + +- 사용자 UI에서 이름 변경 가능 + +- 실제 저장 경로 변경 없이 메타데이터만 변경 가능해야 함 + + +### FR-008 파일 이동 + +- 파일을 다른 폴더로 이동 가능 + +- 실제 저장 파일은 이동하지 않고 메타데이터 위치만 변경 가능해야 함 + + +### FR-009 파일 삭제 + +- 파일 삭제 시 사용자 목록에서 제거 + +- 실제 파일 삭제는 즉시 또는 지연 배치 정책 적용 가능 + + +### FR-010 공유 링크 + +- 파일에 대해 공유 링크 생성 가능 + +- 만료일/비밀번호/활성화 상태 설정 가능 + +- 공유 링크 접근 시 다운로드 가능 + + +### FR-011 미리보기 + +- 이미지/텍스트/PDF 미리보기 가능 + +- 지원하지 않는 형식은 다운로드만 허용 + + +### FR-012 저장 용량 집계 + +- 사용자별 총 사용 용량 계산 가능 + +- 업로드 시 quota 초과 여부 검사 가능 + + +--- + +## 5) 비기능 요구사항 (NFR) + +### NFR-001 성능 (체감 UX 우선) + +- 폴더 목록 조회 응답이 빠르게 느껴져야 함 + +- UI에서 폴더 이동/정렬 시 불필요한 전체 리렌더 최소화 + +- 미리보기는 가능하면 캐싱 사용 + + +### NFR-002 안정성 + +- 업로드 중단/재시도 가능 (tus) + +- 메타데이터(DB)와 파일(Local FS)의 정합성 검증 가능한 구조 + +- 예외 발생 시 사용자에게 명확한 오류 메시지 제공 + + +### NFR-003 보안 + +- 인증/인가 필수 + +- 공유 링크 비밀번호는 평문 저장 금지(해시) + +- 파일 경로 조작(Path Traversal) 방지 + +- 사용자 입력 파일명/폴더명 검증 + +- 업로드 파일 MIME 신뢰 금지(서버 검증 우선) + + +### NFR-004 확장성 + +- 저장소 접근은 인터페이스로 추상화 (`IStorageService`) + +- Local FS 구현과 S3 구현을 교체 가능한 구조로 설계 + +- 미리보기 생성도 별도 서비스 인터페이스로 분리 + + +--- + +## 6) 핵심 설계 원칙 (중요) + +### 원칙 1. “사용자 폴더 구조”와 “실제 디스크 경로”를 분리한다 + +MVP가 로컬FS라도, 실제 디스크에 사용자 폴더 구조를 그대로 반영하지 않는다. + +#### 이유 + +- 파일명/경로 보안 이슈 감소 + +- rename/move 시 파일 이동 비용 제거 + +- S3 전환 시 구조 변경 최소화 + +- 충돌/인코딩/특수문자 이슈 감소 + + +#### 권장 방식 + +- **DB에는 논리 폴더 구조 저장** + +- **디스크에는 object key 기반 저장** + + +예시: + +- 사용자에게 보이는 경로: `/문서/프로젝트/기획서.pdf` + +- 실제 저장 경로: `/data/objects/ab/cd/` + +- DB 매핑: + + - display_name = `기획서.pdf` + + - folder_id = `...` + + - storage_key = `ab/cd/` + + +--- + +### 원칙 2. 업로드 완료 전까지 “파일 엔트리 확정” 금지 + +tus 업로드는 중간 상태가 있으므로 업로드 세션과 최종 파일 엔트리를 분리한다. + +- 업로드 중: `UploadSession` + +- 완료 후: `FileItem` 생성 (또는 상태 전환) + + +--- + +### 원칙 3. 공유 링크는 파일 권한과 별도 정책으로 관리 + +공유 링크는 사용자 인증과 별도로 동작하므로 별도 엔티티/검증 흐름 필요. + +- 만료일 + +- 비밀번호 + +- 활성화 여부 + +- 다운로드 횟수(선택) + + +--- + +## 7) 시스템 구성 (MVP 아키텍처 초안) + +### 7-1. 구성 요소 + +- **Frontend (Blazor)** + 파일 탐색 UI / 업로드 UI / 미리보기 / 공유 설정 + +- **Backend API (ASP.NET Core)** + 인증, 파일/폴더 메타데이터, 공유, 다운로드, 미리보기 라우팅 + +- **Upload Endpoint (tus)** + tus 프로토콜 처리, 업로드 세션 관리, 완료 콜백 + +- **Database (예: PostgreSQL/MySQL)** + 사용자/폴더/파일/공유링크/업로드세션 메타데이터 + +- **Local FS** + + - object 파일 저장 + + - 임시 업로드 파일 + + - 미리보기/썸네일 캐시 + +- Redis + 업로드, 다운로드 토큰 캐싱 등 +### 7-2. 디렉토리 구조 예시 + +```text +/data + /objects # 최종 파일 저장 + /ab/cd/ + /uploads-temp # tus 임시 조각/세션 파일 + /previews # 미리보기 캐시(이미지 썸네일, 텍스트 캐시 등) + /trash # (선택) 지연 삭제 보관 +``` + +--- + +## 8) 도메인 모델 (MVP 기준) + +## 8-1. 엔티티 목록 + +### User + +- id + +- email(or loginId) + +- password_hash + +- display_name + +- role (admin / user) + +- created_at + +- last_login_at + +- storage_allowed_bytes (null이면 무한) + +- storage_used_bytes + +### Folder + +- id + +- owner_user_id + +- parent_folder_id (nullable for root) + +- name + +- full_path + +- created_at + +- updated_at + +- deleted_at + + +### FileItem (사용자 관점 파일 메타데이터) + +- id + +- owner_user_id + +- folder_id + +- display_name + +- mime_type + +- size_bytes + +- checksum_sha256 (선택) + +- storage_key (LocalFS 실제 경로 키) + +- metadata_json + +- preview_status (NONE/PENDING/READY/FAILED) + +- created_at + +- updated_at + +- deleted_at + + +### UploadSession + +- id + +- user_id + +- token (public identifier) + +- target_folder_id + +- original_file_name + +- expected_size + +- received_size + +- tus_upload_id + +- status (CREATED/UPLOADING/COMPLETED/FAILED/ABORTED) + +- temp_path_or_key + +- created_at + +- completed_at + + +### ShareLink + +- id + +- file_id + +- owner_user_id + +- token (public identifier) + +- password_hash (nullable) + +- expires_at (nullable) + +- is_active + +- created_at + +- last_accessed_at + +- access_count + + +### AuditLog (간단 버전) + +- id + +- actor_user_id (nullable for public share access) + +- action_type (UPLOAD, DELETE, SHARE_CREATE...) + +- target_type (FILE, FOLDER, SHARE_LINK) + +- target_id + +- metadata_json + +- created_at + + +--- + +## 9) 데이터 모델 정책 (중요한 구현 규칙) + +### 9-1. 폴더 중복 이름 정책 (권장) + +**초기엔 동일 부모 내 이름 중복 비허용** +(파일/폴더 각각 별도 정책 가능하지만, MVP에서는 단순화) + +### 9-2. 삭제 정책 (권장) + +- **MVP:** 소프트 삭제(`deleted_at`) + 실제 파일 즉시 삭제 or 지연삭제 중 택1 + +- 추천: + + - 메타데이터는 소프트 삭제 + + - 실제 파일은 즉시 삭제 (MVP 단순) + + - 단, 장애 복구 필요하면 trash 디렉토리로 이동 후 배치 삭제 + + +### 9-3. 파일명 정책 + +- 저장 경로에 사용자 파일명 직접 사용 금지 + +- 표시용 이름은 DB에만 저장 + +- 위험 문자/길이 제한 검증 + + +### 9-4. 권한 정책 (MVP) + +- 기본은 owner-only + +- 공유 링크 접근은 `ShareLink` 검증 성공 시 다운로드 허용 + +- 폴더 공유는 MVP 제외 + + +--- + +## 10) API 설계 초안 (MVP) + +> REST 기준 초안. 실제 구현 시 `/api/v1` prefix 권장 + +## 10-1. 인증 + +- `POST /auth/register` + +- `POST /auth/login` + +- `POST /auth/logout` + +- `GET /auth/me` + + +## 10-2. 폴더 + +- `GET /folders/root` → 루트 폴더 정보 + +- `GET /folders/{folderId}/children` → 하위 폴더/파일 목록 + +- `POST /folders` → 폴더 생성 + +- `PATCH /folders/{folderId}` → 이름 변경 / 이동(부모 변경) + +- `DELETE /folders/{folderId}` → 삭제 + + +## 10-3. 파일 메타데이터 + +- `GET /files/{fileId}` → 상세 조회 + +- `PATCH /files/{fileId}` → 이름 변경 / 폴더 이동 + +- `DELETE /files/{fileId}` → 삭제 + + +## 10-4. 업로드 (tus 연동) + +- `POST /uploads/init` (선택) → 업로드 타겟 폴더/메타 사전 등록 + +- `/{tus-endpoint}` → tus 프로토콜 엔드포인트 + +- `POST /uploads/{uploadSessionId}/complete` (선택, tus 훅 기반이면 불필요) + + +> 구현 방식은 라이브러리(tusdotnet 등)에 따라 달라질 수 있음. +> 핵심은 **업로드 세션 → 최종 파일 메타 생성** 흐름 분리. + +## 10-5. 다운로드 / 미리보기 + +- `GET /files/{fileId}/download` + +- `GET /files/{fileId}/preview` + +- `GET /share/{token}` → 공유 링크 메타(비밀번호 필요 여부 등) + +- `POST /share/{token}/access` → 비밀번호 제출 후 다운로드 토큰 발급(선택) + +- `GET /share/{token}/download` + + +## 10-6. 공유 링크 관리 + +- `POST /files/{fileId}/share-links` + +- `GET /files/{fileId}/share-links` + +- `PATCH /share-links/{shareLinkId}` + +- `DELETE /share-links/{shareLinkId}` (비활성화 처리) + + +--- + +## 11) 업로드/다운로드 흐름 (개발 구현 기준) + +## 11-1. 업로드 흐름 (tus, MVP) + +1. 클라이언트가 업로드 대상 폴더 선택 + +2. 업로드 세션 생성 (`UploadSession`) + +3. tus 업로드 시작 (청크 전송) + +4. 업로드 완료 이벤트/콜백 수신 + +5. 서버가 임시 파일 검증 + + - 파일 크기 + + - MIME 추정 + + - quota 확인 + +6. Local FS 최종 경로로 파일 이동 + +7. `FileItem` 생성 + +8. 미리보기 작업 큐 등록(또는 동기/비동기 처리) + +9. 응답 반환, 목록 갱신 + + +### 실패 처리 + +- 완료 전 실패 → `UploadSession = FAILED` + +- quota 초과 → 최종 확정 실패, 임시 파일 정리 + +- 중단 → 재개 가능 상태 유지 + + +--- + +## 11-2. 다운로드 흐름 + +1. 인증 사용자 또는 공유 링크 접근 + +2. 파일 권한/공유 상태 검증 + +3. `storage_key` → Local FS 경로 resolve + +4. 파일 스트림 응답 (Range 지원 권장) + +5. 로그 기록 / 카운트 증가(공유 링크일 경우) + + +--- + +## 11-3. 미리보기 흐름 + +### 이미지 + +- 원본 또는 썸네일 반환 + +- 썸네일 없으면 생성 후 캐시 + + +### 텍스트 + +- 크기 제한 내에서 UTF-8 등 디코딩 시도 + +- 너무 큰 파일은 일부만 미리보기 + + +### PDF + +- 브라우저 내장 뷰어 활용 (`Content-Type: application/pdf`) + +- 필요 시 인라인 응답 + + +--- + +## 12) 로컬FS 저장소 설계 (MVP 구체안) + +## 12-1. 저장소 인터페이스 (추상화) + +MVP가 로컬FS여도 인터페이스는 반드시 둔다. + +예시 (개념): + +- `SaveAsync(stream, metadata) -> storageKey` + +- `OpenReadAsync(storageKey)` + +- `DeleteAsync(storageKey)` + +- `MoveTempToObjectAsync(tempKey, storageKey)` + +- `ExistsAsync(storageKey)` + +- `GetAbsolutePath(storageKey)` (LocalFS 구현 전용) + + +### 구현체 + +- `LocalFileStorageService` (MVP) + +- `S3ObjectStorageService` (추후) + + +--- + +## 12-2. Local FS 저장 키 전략 (권장) + +`storage_key = {2자리}/{2자리}/{uuid}` + +예시: + +- `a3/f1/6f5c0a6e-...` + + +장점: + +- 디렉토리 당 파일 수 분산 + +- S3 키로 전환해도 재사용 가능 + +- 파일명/경로 공격 방지 쉬움 + + +--- + +## 13) 보안/검증 체크리스트 (MVP 필수) + +### 업로드 + +- 허용 최대 크기 제한 + +- 파일명 길이 제한 + +- 위험 확장자 정책(차단/허용 리스트) + +- MIME 타입은 클라이언트 값 신뢰하지 않기 + +- 경로 결합 시 Path Traversal 방지 + + +### 공유 링크 + +- 토큰은 추측 어려운 랜덤값 + +- 비밀번호 해시 저장 + +- 만료일 검증 + +- 비활성화 상태 검증 + + +### 인증/인가 + +- 모든 사용자 API는 소유권 검증 필수 + +- 파일 ID 기반 접근 시 owner 검증 누락 금지 + +- 예외 메시지에 내부 경로 노출 금지 + + +--- + +## 14) 로깅/모니터링 (초기 최소 기준) + +### 애플리케이션 로그 + +- 인증 실패 + +- 업로드 시작/완료/실패 + +- 파일 삭제 + +- 공유 링크 생성/삭제 + +- 미리보기 생성 실패 + + +### 운영 지표(나중에 Prometheus 가능) + +- 업로드 성공률 + +- 업로드 평균 처리시간 + +- 폴더 목록 조회 응답시간 + +- 미리보기 생성 성공률 + +- 저장 용량 사용량 + + +--- + +## 15) 테스트 전략 (개발용) + +## 15-1. 단위 테스트 + +- 파일명/폴더명 검증 로직 + +- quota 계산/검사 + +- 공유 링크 만료/비밀번호 검증 + +- 권한 검사 로직 + +- storage key 생성 규칙 + + +## 15-2. 통합 테스트 + +- 회원가입/로그인 플로우 + +- 폴더 생성/조회 + +- 파일 업로드 완료 후 메타데이터 생성 + +- 다운로드 권한 검사 + +- 공유 링크 다운로드 + +- 삭제 후 목록 반영 + + +## 15-3. 수동 E2E 시나리오 (MVP 검증) + +- 대용량 파일 업로드 중 네트워크 끊김 → 재개 + +- 이미지/PDF 미리보기 확인 + +- 공유 링크 만료 확인 + +- quota 초과 업로드 차단 확인 + + +--- + +## 16) 개발 우선순위 / 구현 순서 (권장) + +### Phase 1: 기반 구축 + +1. 인증/회원 + +2. DB 스키마(User/Folder/FileItem) + +3. 루트 폴더/목록 API + +4. LocalFS 저장소 인터페이스 + 구현 + + +### Phase 2: 핵심 파일 기능 + +5. 파일 업로드(tus) + +6. 업로드 완료 후 FileItem 확정 + +7. 다운로드 API + +8. 파일/폴더 rename/move/delete + + +### Phase 3: 사용자 경험 강화 + +9. 미리보기(이미지/텍스트/PDF) + +10. 공유 링크 생성/다운로드 + +11. quota 집계/제한 + +12. 기본 로그/에러 메시지 정리 + + +--- + +## 17) MVP 완료 기준 (Definition of Done) + +다음 조건을 충족하면 MVP 개발 완료로 판단: + +- 사용자가 회원가입/로그인 가능 + +- 폴더 생성 및 파일 목록 탐색 가능 + +- 파일 업로드/다운로드 가능 + +- 네트워크 중단 후 업로드 재개 가능 (tus) + +- 파일명 변경/이동/삭제 가능 + +- 이미지/텍스트/PDF 미리보기 가능 + +- 공유 링크 생성 및 외부 다운로드 가능 + +- 사용자별 저장 용량 제한이 동작함 + +- 주요 예외 상황에서 사용자 친화적 에러 응답 제공 + +- 기본 테스트(핵심 플로우) 통과 + + +--- + +## 18) 향후 확장 고려사항 (지금 설계에 반영만) + +MVP에서는 구현하지 않지만, 지금 구조에 흔적은 남겨두는 것이 좋음. + +- `IStorageService` 추상화 (S3/MinIO 전환 대비) + +- `Workspace` 개념 확장 가능성 (개인공간 → 공유공간) + +- WebDAV 엔드포인트 추가 가능한 라우팅 구조 + +- Background Job 구조 (미리보기/바이러스 스캔/외부 다운로드) + +- 권한 모델 확장 (owner-only → role-based) + \ No newline at end of file diff --git a/기획/제안서.md b/기획/제안서.md new file mode 100644 index 0000000..59a6f65 --- /dev/null +++ b/기획/제안서.md @@ -0,0 +1,369 @@ +# Cloud# 서비스 제안서 + +## 목차 + +1. 프로젝트 개요 +2. 문제 정의 +3. 해결 방향 +4. 핵심 가치 제안 및 차별점 +5. 타겟 사용자 +6. 기능 로드맵 +7. 기술 아키텍처 +8. 데이터 모델 +9. 비기능 요구사항 +10. 개발 일정 +11. 성공 지표 (KPI) +12. 리스크 및 대응 전략 +13. 기대 효과 +--- + +## 1. 프로젝트 개요 + +|항목|내용| +|---|---| +|**서비스명**|Cloud#| +|**한 줄 소개**|느린 웹 기반 파일 관리의 UX를 개선하고, S3 성능과 확장성을 갖춘 차세대 파일 호스팅 서비스| +|**Backend**|ASP.NET Core| +|**Frontend**|Blazor (Server 또는 WASM + API 조합 검토)| +|**업로드 방식**|tus 프로토콜 (재개 가능한 대용량 업로드)| +|**저장소**|S3 호환 Object Storage (MinIO / AWS S3 / Ceph RGW)| +|**개발 방식**|단계별 로드맵 — MVP → 확장 기능 → 커뮤니티 플랫폼| + +--- + +## 2. 문제 정의 + +기존 파일 관리 솔루션은 두 가지 방향에서 한계를 드러냅니다. + +### 2.1 Nextcloud 계열의 한계 + +- 웹 UI 전반의 **체감 반응성 저하** — 탐색, 공유 설정, 미리보기, 페이지 전환에서 답답함 발생 +- 구형 기술 스택 기반으로 **성능 최적화 및 유지보수 비용 증가** +- 무거운 기능 구조로 인해 기본적인 파일 관리 경험조차 느리게 느껴짐 + +### 2.2 S3 저장소의 한계 + +- 성능과 안정성은 우수하나 **파일 관리 UX 기능 부족** +- 폴더 구조, 공유 링크, 미리보기, 파일 정리 기능이 불친절하거나 부재 +- **비개발자/일반 사용자에게 높은 진입 장벽** 존재 + +### 2.3 시장 공백 + +```mermaid +flowchart TB + A["Nextcloud
기능은 풍부
UX가 느림"] + B["S3 저장소
성능은 우수
UX가 불친절"] + C["Cloud#
빠르고 · 쉽고 · 안정적"] + + A --> C + B --> C +``` + + +--- + +## 3. 해결 방향 + +**"Nextcloud의 기능성 + S3의 성능/확장성 + 현대적인 웹 UX"** + +|기능성|성능·확장성|현대적 UX| +|---|---|---| +|Nextcloud 수준의 파일 관리|S3/Object Storage 기반 인프라|Blazor + 빠른 API 응답| + +--- + +## 4. 핵심 가치 제안 및 차별점 + +### 4.1 핵심 가치 제안 + +|가치|설명| +|---|---| +|⚡ **빠르다**|클릭·탐색·미리보기 반응 속도 개선| +|🎯 **쉽다**|폴더·공유·정리 기능의 직관적 UX| +|🔒 **안정적이다**|tus 기반 대용량 업로드 중단 후 재개 가능| +|📈 **확장 가능하다**|S3 기반으로 저장소 교체·증설 용이| + +### 4.2 경쟁 서비스 대비 차별점 + +|구분|Nextcloud|S3 직접 사용|**Cloud#**| +|---|---|---|---| +|UI 반응 속도|느림|제한적|**빠름 (최우선 목표)**| +|대용량 업로드 안정성|보통|지원|**tus 기반 완전 지원**| +|일반 사용자 친화성|보통|낮음|**높음 (직관적 UX)**| +|저장소 확장성|제한적|우수|**우수 (S3 호환)**| +|WebDAV 지원|지원|미지원|**2차 개발 예정**| +|커뮤니티/협업 기능|제한적|미지원|**3차 개발 예정**| + +--- + +## 5. 타겟 사용자 + +### 5.1 1차 타겟 + +- 개인 개발자 / 홈서버 운영자 +- 소규모 팀 (스터디, 프로젝트 팀, 동아리) +- NAS/클라우드 대체 솔루션을 탐색 중인 사용자 + +### 5.2 2차 타겟 + +- 크리에이터/디자이너 — 파일 공유·미리보기 수요 높음 +- 내부 자료 공유가 필요한 팀/조직 +- WebDAV 기반 마운트를 원하는 파워유저 + +### 5.3 사용자 니즈 + +- 빠른 업로드·다운로드 +- 쉬운 폴더·파일 정리 +- 링크 공유 및 권한 제어 +- 브라우저에서의 미리보기 +- OS 탐색기에서 직접 접근 (WebDAV) + +--- + +## 6. 기능 로드맵 + +### Phase 1 — MVP (4~8주) + +> 목표: 실사용 가능한 최소 제품 완성 + +**회원/인증** + +- 회원가입, 로그인/로그아웃 +- JWT + Refresh Token 인증 +- 비밀번호 재설정 (이메일 기반) + +**파일 관리** + +- 파일 업로드 — tus 기반, 재개 가능 +- 파일 다운로드 (Range 지원) +- 폴더 생성·이동·이름 변경·삭제 +- 파일 이름 변경·이동·삭제 +- 파일 목록 조회 (정렬/검색 기본) +- 휴지통 (소프트 삭제) + +**공유** + +- 공유 링크 생성 +- 만료일·비밀번호 설정 +- 읽기 전용 공유 +- 링크 비활성화 + +**미리보기** + +- 이미지 미리보기 +- 텍스트/코드 파일 미리보기 +- PDF 미리보기 (브라우저 내장 뷰어) + +**관리자/운영** + +- 사용자별 저장 용량 제한 (Quota) +- 파일 업로드 크기 제한 +- 관리자용 사용자·용량 현황 조회 + +--- + +### Phase 2 — 확장 기능 (3~6주) + +> 목표: 파워유저·운영자 사용성 강화 + +**WebDAV 지원** + +- OS 탐색기/Finder에서 네트워크 드라이브처럼 접근 +- 사용자별 권한 반영 +- Windows/macOS 우선 지원 + +**외부 다운로드/수집** + +- URL 기반 파일 가져오기 (Remote Fetch) +- 서버 측 다운로드 큐 처리 및 진행률 표시 + +**고급 파일 관리** + +- 태그·즐겨찾기 +- 최근 파일 +- 버전 관리 (간단 버전) +- 중복 파일 탐지 (해시 기반) + +**운영 기능** + +- 감사 로그 (업로드·삭제·공유 생성) +- 관리자 권한 정책 (RBAC) +- 알림 — 공유 링크 만료, 용량 초과 등 + +--- + +### Phase 3 — 커뮤니티 플랫폼 (추후) + +> 목표: 파일 공유 중심 커뮤니티 플랫폼으로 확장 + +**공유 스페이스** + +- 주제/팀 단위 공간 생성 +- 공간별 권한 (관리자/멤버/읽기전용) +- 공간별 저장소·용량 할당 + +**커뮤니티/채팅** + +- 파일 중심 채팅·피드 +- 파일 업로드 후 즉시 공유·대화 +- 링크·미디어·문서 프리뷰 +- 파일·메시지 통합 검색 + +**장기 확장** + +- 봇/자동화 업로드 +- 팀 워크플로우 연동 +- 실시간 협업 편집기 연동 + +--- + +## 7. 기술 아키텍처 + +```mermaid +flowchart TB + Client["클라이언트
Blazor UI + tus client"] + + API["API 서버
ASP.NET Core — 인증/인가, 메타데이터,
공유 링크, WebDAV(2차), 관리자 API"] + + Upload["업로드 서비스
tus 세션 관리
청크 병합
이벤트 발행"] + + DB["메타데이터 DB
PostgreSQL / MySQL
사용자·폴더·파일·공유
링크·감사로그 관리"] + + Storage["S3 호환 Object Storage
MinIO / AWS S3 / Ceph RGW
파일 본문(binary) · 썸네일·미리보기 캐시"] + + Worker["비동기 작업자 (선택)
썸네일 생성 · 미리보기 변환
바이러스 스캔 · 원격 URL 다운로드"] + + Client --> API + API --> Upload + API --> DB + Upload --> Storage + Storage --> Worker +``` + + +### 기술 선택 근거 + +|기술|선택 이유| +|---|---| +|ASP.NET Core|높은 성능, WebDAV/S3 SDK 지원, 풍부한 생태계| +|Blazor|C# 풀스택으로 컨텍스트 전환 최소화| +|tus 프로토콜|표준화된 재개 가능 업로드 — 네트워크 중단에 강인| +|S3 호환 저장소|MinIO(온프레미스)~AWS S3까지 교체 가능한 유연한 구조| + +--- + +## 8. 데이터 모델 + +|엔티티|설명| +|---|---| +|`User`|사용자 계정 — 인증 정보, 저장 용량 Quota| +|`Workspace`|개인/공유 공간 단위| +|`Folder`|폴더 메타데이터 — 계층 구조| +|`FileItem`|파일 메타데이터 — 이름, 크기, MIME, 해시, S3 저장 키| +|`FileVersion`|파일 버전 정보 (선택)| +|`ShareLink`|공유 링크 — 만료일, 비밀번호, 권한| +|`Permission`|사용자/공간/폴더 권한| +|`UploadSession`|tus 업로드 상태 — 청크 진행률, 재개 정보| +|`PreviewAsset`|썸네일·미리보기 캐시| +|`AuditLog`|주요 이벤트 로그 — 업로드·삭제·공유 생성| + +--- + +## 9. 비기능 요구사항 + +### 9.1 성능 + +- 목록 조회·폴더 이동 UI 빠른 응답 — **체감 속도 최우선** +- 대용량 업로드 안정성 보장 (재개 가능) +- 썸네일·미리보기 캐싱으로 반복 요청 최적화 + +### 9.2 안정성 + +- 업로드 중단·재시도 처리 +- 저장소 장애 대응 (재시도/에러 처리) +- 파일 메타데이터와 저장 객체 정합성 검증 배치 + +### 9.3 보안 + +- JWT 인증/인가 분리 +- 공유 링크 권한·만료·비밀번호 보호 +- 악성 파일 업로드 대응 (백신 스캔 연계) +- 감사 로그 / 접근 로그 +- HTTPS 전제 + +### 9.4 확장성 + +- 저장소 백엔드 교체 가능 (MinIO ↔ AWS S3 등) +- 모듈형 설계 — WebDAV·커뮤니티 기능 추가 용이 +- API/도메인 분리로 수평 확장 대응 + +--- + +## 10. 개발 일정 + +|단계|기간|주요 내용| +|---|---|---| +|**Phase 0** — 기획/설계|1~2주|요구사항 확정, IA/화면 흐름 설계, DB·저장소 구조 설계, PoC (tus + S3 + 미리보기)| +|**Phase 1** — MVP|4~8주|인증/회원, 파일/폴더 CRUD, tus 업로드·다운로드, 공유 링크, 미리보기 기본| +|**Phase 2** — 확장 기능|3~6주|WebDAV, URL 가져오기, 관리자 기능 강화, 감사 로그·알림| +|**Phase 3** — 커뮤니티|추후 협의|공유 스페이스, 채팅·피드, 공간 권한·통합 검색| + +> 실제 일정은 인원수·숙련도·디자인 리소스에 따라 조정 필요 + +### 개발 우선순위 + +|우선순위|항목| +|---|---| +|**Must**|인증/회원, 파일/폴더 메타데이터, tus 업로드, 다운로드, 공유 링크, 이미지/PDF/텍스트 미리보기, Quota 설정| +|**Should**|휴지통, 즐겨찾기/최근 파일, 관리자 대시보드, 썸네일 캐싱 고도화| +|**Could**|WebDAV, URL 가져오기, 파일 버전 관리, 커뮤니티/채팅, 고급 검색/태그| + +--- + +## 11. 성공 지표 (KPI) + +### MVP 단계 + +|지표|설명| +|---|---| +|업로드 성공률|목표: 99%+| +|업로드 재개 성공률|중단 후 재개 성공 비율| +|파일 목록 조회 응답시간|목표: 200ms 이하| +|미리보기 생성 성공률|이미지·PDF·텍스트 기준| +|공유 링크 사용률|생성 대비 다운로드 전환율| +|DAU/WAU|초기 사용자 활성도| + +### UX 중심 + +|지표|설명| +|---|---| +|TTFU|첫 파일 업로드까지 걸리는 시간| +|공유 링크 생성 클릭 수|생성까지 평균 클릭 수 최소화| +|사용자 만족도|체감 속도·사용성 설문| + +--- + +## 12. 리스크 및 대응 전략 + +|리스크|원인|대응 전략| +|---|---|---| +|**빠른 UX 달성 실패**|서버 렌더링 지연, DB 쿼리 비효율|목록·탐색 API 최적화, 캐시 적용, 미리보기 비동기 생성, 성능 지표 관리| +|**대용량 업로드 안정성**|네트워크 중단, 청크 정합성 문제|tus 채택, 업로드 세션 상태 관리, 재시도 정책·체크섬 검증| +|**WebDAV 호환성**|OS별 클라이언트 동작 차이|2차 기능으로 분리, Windows/macOS 우선, 점진적 확장| +|**저작권·불법 사용**|외부 다운로드 기능 악용 가능성|사용자 소유/허가 콘텐츠 한정, 이용약관 명시, 신고·차단·로그 정책 마련| + +--- + +## 13. 기대 효과 + +### 사용자 측면 + +- 기존 솔루션 대비 **빠른 파일 관리 경험** 제공 +- 단순 저장소를 넘어선 **실사용 중심 파일 작업 공간** +- 대용량 업로드·공유·미리보기의 편의성 향상 + +### 개발·운영 측면 + +- 현대 기술 스택 기반 **유지보수성 향상** +- 저장소와 메타데이터 분리로 **확장성 확보** +- 단계적 기능 확장 — 파일 호스팅 → 팀 공유 → 커뮤니티 플랫폼 \ No newline at end of file diff --git a/설계/db/개념적 설계.md b/설계/db/개념적 설계.md new file mode 100644 index 0000000..a7accaa --- /dev/null +++ b/설계/db/개념적 설계.md @@ -0,0 +1,351 @@ +# Cloud# — 데이터베이스 개념적 설계서 + +> 본 문서는 Cloud# 서비스의 핵심 엔티티에 대한 개념적 DB 설계를 정의한다. +> 물리적 DDL이 아닌 **엔티티의 역할, 컬럼 의미, 설계 의도, 제약 조건**을 중심으로 기술한다. + +--- + +## 목차 + +1. [엔티티 목록](#1. 엔티티 목록) +2. [ER 다이어그램](#2-er-다이어그램) +3. [엔티티 상세 설계](#3-엔티티-상세-설계) + - [3.1 User](#31-user) + - [3.2 Folder](#32-folder) + - [3.3 FileItem](#33-fileitem) + - [3.4 UploadSession](#34-uploadsession) +4. [관계 정의](#4-관계-정의) +5. [제약 조건 요약](#5-제약-조건-요약) +6. [설계 결정 사항 (Decision Log)](#6-설계-결정-사항-decision-log) + +--- + +## 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 | 소프트 삭제 일시 | + +#### 설계 포인트 + +- `email` 은 **UNIQUE** 제약으로 중복 가입 방지 +- `storage_allowed_bytes` 가 `NULL` 이면 무제한 처리 + - 애플리케이션 레이어에서 `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_key` 와 `display_name` 분리** + +``` +display_name : 사용자에게 보이는 이름 → "보고서 최종.pdf" +storage_key : 저장소의 실제 키 → "user/12/ab/cd/f83e...uuid.bin" +``` + +- 파일 이름 변경 시 `display_name` 만 변경하고 저장소 객체는 그대로 유지 +- `storage_key` 가 외부에 노출되지 않도록 주의 + +**`metadata_json` 활용 예시** + +```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. 관계 정의 + +| 관계 | 카디널리티 | 설명 | +|------|-----------|------| +| `User` → `Folder` | 1 : N | 한 사용자는 여러 폴더를 소유 | +| `Folder` → `Folder` | 1 : N | 폴더는 하위 폴더를 가짐 (자기참조) | +| `User` → `FileItem` | 1 : N | 한 사용자는 여러 파일을 소유 | +| `Folder` → `FileItem` | 1 : N | 한 폴더는 여러 파일을 포함 | +| `User` → `UploadSession` | 1 : N | 한 사용자는 여러 업로드 세션을 가짐 | +| `Folder` → `UploadSession` | 1 : N | 한 폴더는 여러 업로드 세션의 목적지가 됨 | +| `UploadSession` → `FileItem` | 1 : 0..1 | 완료된 세션은 하나의 FileItem을 생성 | + +--- + +## 5. 제약 조건 요약 + +### User + +| 제약 | 내용 | +|------|------| +| PK | `id` | +| UNIQUE | `email` | +| CHECK | `storage_used_bytes >= 0` | + +### Folder + +| 제약 | 내용 | +|------|------| +| PK | `id` | +| FK | `owner_user_id` → `User.id` NOT NULL | +| FK | `parent_folder_id` → `Folder.id` NULL 허용 | +| UNIQUE | `(owner_user_id, parent_folder_id, name)` — 활성 데이터 기준 | +| 정책 | 사용자당 루트 폴더(`parent_folder_id IS NULL`) 1개 권장 | + +### FileItem + +| 제약 | 내용 | +|------|------| +| PK | `id` | +| FK | `owner_user_id` → `User.id` NOT NULL | +| FK | `folder_id` → `Folder.id` NOT NULL | +| UNIQUE | `storage_key` | +| UNIQUE | `(owner_user_id, folder_id, display_name)` — 활성 데이터 기준 | +| CHECK | `size_bytes >= 0` | + +### UploadSession + +| 제약 | 내용 | +|------|------| +| PK | `id` | +| FK | `owner_user_id` → `User.id` NOT NULL | +| FK | `target_folder_id` → `Folder.id` NOT NULL | +| FK | `file_item_id` → `FileItem.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_key` 와 `display_name` 분리 | 파일 이름 변경이 저장소 객체 이동 없이 메타데이터 변경만으로 처리 가능 | +| 4 | `UploadSession` 완료 처리를 단일 트랜잭션으로 | `FileItem` 생성과 `storage_used_bytes` 증가의 정합성 보장 | +| 5 | 소프트 삭제 (`deleted_at`) 적용 | 실수 복구, 휴지통 기능 지원. 유니크 제약은 `deleted_at IS NULL` 조건부 인덱스로 처리 | +| 6 | `token` (외부) / `id` (내부) 식별자 분리 | 내부 PK 노출 방지. 클라이언트는 `token` 으로만 업로드 세션 접근 | + +--- \ No newline at end of file diff --git a/설계/img/개념적설계_erd.svg b/설계/img/개념적설계_erd.svg new file mode 100644 index 0000000..87bcc14 --- /dev/null +++ b/설계/img/개념적설계_erd.svg @@ -0,0 +1,102 @@ +

USER

bigint

id

PK

string

email

string

role

bigint

storage_allowed_bytes

bigint

storage_used_bytes

FOLDER

bigint

id

PK

bigint

owner_user_id

FK

bigint

parent_folder_id

FK

string

name

string

full_path

datetime

deleted_at

FILE_ITEM

bigint

id

PK

bigint

owner_user_id

FK

bigint

folder_id

FK

string

display_name

string

storage_key

bigint

size_bytes

string

mime_type

string

preview_status

json

metadata_json

datetime

deleted_at

UPLOAD_SESSION

bigint

id

PK

bigint

owner_user_id

FK

bigint

target_folder_id

FK

string

token

UK

string

tus_upload_id

string

status

bigint

expected_size

bigint

received_size

string

storage_key_temp

datetime

created_at

datetime

expires_at

owns

owns

creates

parent_of

contains

target

\ No newline at end of file diff --git a/설계/기능요구사항.md b/설계/기능요구사항.md new file mode 100644 index 0000000..5523a90 --- /dev/null +++ b/설계/기능요구사항.md @@ -0,0 +1,33 @@ + +| FR ID | 기능명 | 설명 | 입력 | 출력 | 예외 | 우선순위 | +| ------ | -------------- | ------------------------------------------------------------------------------------ | ------------------------- | -------------------------- | -------------------------------------- | ---- | +| FR-001 | 회원가입 | 비회원은 이메일 또는 아이디와 비밀번호를 이용해 계정을 생성할 수 있어야 한다. 시스템은 계정 정보를 저장하고 이후 로그인 가능 상태로 전환해야 한다. | 이메일 또는 아이디, 비밀번호 | 회원가입 성공/실패 결과, 생성된 사용자 정보 | 이미 존재하는 계정, 비밀번호 정책 미충족, 필수값 누락 | 높음 | +| FR-002 | 로그인 | 사용자는 등록된 계정 정보로 로그인할 수 있어야 하며, 로그인 성공 시 인증 상태를 획득해야 한다. | 이메일 또는 아이디, 비밀번호 | 로그인 성공/실패 결과, 인증 세션 또는 토큰 | 계정 없음, 비밀번호 불일치, 비활성 계정 | 높음 | +| FR-003 | 로그아웃 | 로그인한 사용자는 현재 인증 세션 또는 토큰을 종료할 수 있어야 한다. | 인증 정보(세션/토큰) | 로그아웃 성공/실패 결과 | 인증 정보 없음, 이미 만료된 세션/토큰 | 높음 | +| FR-004 | 인증 세션 유지 | 로그인한 사용자는 재인증 없이 보호된 API를 사용할 수 있어야 하며, 시스템은 인증 상태를 유지해야 한다. | 세션 쿠키 또는 JWT 토큰 | 인증된 사용자 컨텍스트, 보호 API 접근 허용 | 만료된 세션/토큰, 위조 또는 무효 토큰 | 높음 | +| FR-005 | 기본 프로필 조회 | 로그인한 사용자는 자신의 기본 프로필 정보를 조회할 수 있어야 한다. | 인증 정보 | 사용자 프로필 정보 | 인증 실패, 존재하지 않는 사용자 | 중간 | +| FR-006 | 루트 폴더 자동 생성 | 시스템은 회원가입 완료 시 사용자 전용 루트 폴더를 자동으로 생성해야 한다. | 사용자 식별 정보 | 루트 폴더 생성 결과 | 루트 폴더 생성 실패, 사용자 생성 실패 | 높음 | +| FR-007 | 루트 폴더 조회 | 로그인한 사용자는 자신의 루트 폴더 및 최상위 파일/폴더 목록에 접근할 수 있어야 한다. | 인증 정보 | 루트 폴더 정보, 하위 파일/폴더 목록 | 인증 실패, 루트 폴더 미존재 | 높음 | +| FR-008 | 폴더 생성 | 사용자는 특정 부모 폴더 하위에 새 폴더를 생성할 수 있어야 한다. | 부모 폴더 ID, 폴더명 | 생성된 폴더 정보 | 부모 폴더 없음, 권한 없음, 중복 이름 정책 위반 | 높음 | +| FR-009 | 폴더명 변경 | 사용자는 기존 폴더의 이름을 변경할 수 있어야 한다. 실제 저장 경로가 아니라 메타데이터 기준으로 처리한다. | 폴더 ID, 새 폴더명 | 변경된 폴더 정보 | 대상 폴더 없음, 권한 없음, 중복 이름 정책 위반 | 중간 | +| FR-010 | 폴더 삭제 | 사용자는 폴더를 삭제할 수 있어야 한다. 비어 있지 않은 폴더의 삭제는 시스템 정책에 따라 처리한다. | 폴더 ID | 삭제 성공/실패 결과 | 대상 폴더 없음, 권한 없음, 하위 항목 존재, 루트 폴더 삭제 시도 | 중간 | +| FR-011 | 파일 업로드 초기화 | 사용자는 업로드를 시작하기 위해 파일 메타데이터와 업로드 요청을 등록할 수 있어야 한다. | 파일명, 크기, 타입, 대상 폴더 ID | 업로드 세션 정보, 업로드 URL | 권한 없음, quota 초과, 파일 크기 제한 초과, 대상 폴더 없음 | 높음 | +| FR-012 | 파일 업로드 진행 및 재개 | 시스템은 대용량 파일 업로드 중 네트워크가 끊겨도 이어서 업로드할 수 있어야 한다. | tus 업로드 세션, 청크 데이터 | 업로드 진행 상태, 재개 가능 상태 | 세션 만료, 손상된 청크, 잘못된 업로드 오프셋 | 높음 | +| FR-013 | 업로드 완료 처리 | 파일 업로드가 완료되면 시스템은 메타데이터를 저장하고 파일 목록에 반영해야 한다. | 업로드 완료 이벤트, 파일 식별 정보 | 저장된 파일 메타데이터, 목록 반영 결과 | 저장 실패, 메타데이터 반영 실패, 파일 무결성 오류 | 높음 | +| FR-014 | 파일 다운로드 | 권한 있는 사용자는 저장된 파일을 다운로드할 수 있어야 한다. | 파일 ID, 인증 정보 | 파일 스트림 또는 다운로드 응답 | 권한 없음, 대상 파일 없음, 삭제된 파일 | 높음 | +| FR-015 | 파일명 변경 | 사용자는 파일명을 변경할 수 있어야 한다. 실제 저장 객체는 유지하고 메타데이터만 수정한다. | 파일 ID, 새 파일명 | 변경된 파일 정보 | 대상 파일 없음, 권한 없음, 중복 이름 정책 위반 | 중간 | +| FR-016 | 파일 이동 | 사용자는 파일을 다른 폴더로 이동할 수 있어야 한다. 실제 바이너리 파일은 이동하지 않고 메타데이터의 부모 폴더만 변경한다. | 파일 ID, 대상 폴더 ID | 이동된 파일 정보 | 대상 파일 없음, 대상 폴더 없음, 권한 없음, 동일 위치 이동 | 중간 | +| FR-017 | 파일 삭제 | 사용자는 파일을 삭제할 수 있어야 하며, 삭제된 파일은 사용자 목록에서 제거되어야 한다. | 파일 ID | 삭제 성공/실패 결과 | 대상 파일 없음, 권한 없음, 이미 삭제된 파일 | 높음 | +| FR-018 | 파일 목록 조회 | 사용자는 특정 폴더 내 파일 및 하위 폴더 목록을 조회할 수 있어야 한다. | 폴더 ID, 인증 정보 | 파일/폴더 목록 | 대상 폴더 없음, 권한 없음 | 높음 | +| FR-019 | 파일 목록 정렬 | 사용자는 파일 목록을 이름, 크기, 수정일 기준으로 정렬할 수 있어야 한다. | 폴더 ID, 정렬 기준, 정렬 방향 | 정렬된 파일/폴더 목록 | 지원하지 않는 정렬 기준, 대상 폴더 없음 | 중간 | +| FR-020 | 공유 링크 생성 | 사용자는 특정 파일에 대해 외부 공유용 다운로드 링크를 생성할 수 있어야 한다. | 파일 ID, 선택 옵션(만료일/비밀번호) | 공유 링크 URL, 링크 메타데이터 | 대상 파일 없음, 권한 없음 | 높음 | +| FR-021 | 공유 링크 옵션 설정 | 사용자는 공유 링크에 대해 만료일, 비밀번호, 활성화 상태를 설정하거나 수정할 수 있어야 한다. | 링크 ID, 만료일, 비밀번호, 활성화 여부 | 변경된 링크 정보 | 대상 링크 없음, 권한 없음, 잘못된 만료일 형식 | 중간 | +| FR-022 | 공유 링크 비활성화 | 사용자는 기존 공유 링크를 비활성화하여 외부 접근을 차단할 수 있어야 한다. | 링크 ID | 비활성화 결과 | 대상 링크 없음, 권한 없음, 이미 비활성화된 링크 | 중간 | +| FR-023 | 공유 링크 다운로드 | 외부 사용자는 유효한 공유 링크를 통해 파일을 다운로드할 수 있어야 한다. | 공유 링크, 비밀번호(필요 시) | 파일 다운로드 응답 | 링크 만료, 링크 비활성화, 비밀번호 불일치, 대상 파일 없음 | 높음 | +| FR-024 | 이미지 미리보기 | 사용자는 지원되는 이미지 파일을 브라우저 내에서 바로 확인할 수 있어야 한다. | 파일 ID | 이미지 미리보기 데이터 또는 URL | 지원하지 않는 형식, 대상 파일 없음, 권한 없음 | 중간 | +| FR-025 | 텍스트 미리보기 | 사용자는 txt, md, json, log 등의 텍스트 파일 내용을 브라우저 내에서 확인할 수 있어야 한다. | 파일 ID | 텍스트 내용 | 지원하지 않는 형식, 인코딩 오류, 파일 크기 초과 | 중간 | +| FR-026 | PDF 미리보기 | 사용자는 PDF 파일을 브라우저 내장 뷰어를 통해 열람할 수 있어야 한다. | 파일 ID | PDF 미리보기 URL 또는 스트림 | 지원하지 않는 형식, 대상 파일 없음, 권한 없음 | 중간 | +| FR-027 | 미지원 형식 처리 | 미리보기를 지원하지 않는 파일은 다운로드만 허용해야 한다. | 파일 ID | 다운로드 가능 상태 정보 | 대상 파일 없음, 권한 없음 | 낮음 | +| FR-028 | 사용자 저장 용량 집계 | 시스템은 사용자별 총 파일 사용량을 계산하고 표시할 수 있어야 한다. | 사용자 ID 또는 인증 정보 | 총 사용 용량, quota 대비 사용률 | 사용자 없음, 집계 실패 | 중간 | +| FR-029 | 업로드 용량 제한 검사 | 시스템은 업로드 요청 시 파일 크기 제한과 사용자 quota 초과 여부를 검사해야 한다. | 사용자 ID, 파일 크기 | 업로드 가능/불가 결과 | quota 초과, 업로드 최대 크기 초과 | 높음 | +| FR-030 | 기본 로그 기록 | 시스템은 업로드, 삭제, 공유 링크 생성 등 주요 이벤트를 로그로 기록해야 한다. | 이벤트 정보, 사용자 정보, 대상 리소스 정보 | 로그 저장 결과 | 로그 저장 실패, 이벤트 정보 누락 | 중간 | \ No newline at end of file diff --git a/설계/무제.md b/설계/무제.md new file mode 100644 index 0000000..e69de29