Files
hop.noname.company/docs/TEMPORARY_VAULT.md

11 KiB
Raw Blame History

hop. 기기 전송·임시 보관함 기준

2026-10-13 사용자 수정안을 반영한 현재 기준이다. 이전 SPEC의 이메일 원격 전송, 익명 전송 내역 화면, 영구 즐겨찾기, 여러 방 동시 참여 및 좌우 분할 화면보다 우선한다.

화면과 전송

새 비밀번호는 가입·재설정·변경 모두 최소 8자다. 가입 이메일 인증을 완료하면 인증한 계정으로 자동 로그인하고 받은 항목을 표시한다. 현재 브라우저의 이전 로그인 세션은 종료하고 다른 기기의 세션은 유지한다. 기존 비밀번호를 일괄 변경하지 않으며 인증 토큰의 일회용·만료·정지 계정 차단 정책을 유지한다.

메인은 중앙의 기기 선택 화면이다. 헤더는 홈으로 돌아가는 로고, 로그인/보관함, 더보기 버튼을 제공한다. 앱 설치·테마·서비스 정보는 더보기 안에 둔다. 기기 목록은 최대 데스크톱 4열, 태블릿 3열, 모바일 2열이며 최대 화면 너비는 1080px이다. 내 기기는 자연스럽게 스크롤되는 푸터의 작은 상태 버튼으로 표시하고, 설정에서는 이름만 변경한다. 발견 허용 스위치는 표시하지 않으며 사이트 접속 시 자동 발견에 참여한다. 이전에 발견을 꺼둔 기기도 재접속 시 허용으로 바꾸고 기기 이름·세션은 유지한다. QR 연결은 기기 카드와 같은 영역의 보조 카드로 둔다. 헤더 로고와 짧은 보조 문구는 작게 표시하고 푸터의 서버 경유 안내는 제거한다.

기기를 누르면 PC 중앙 모달·모바일 하단 시트에서 현재 콘텐츠 하나를 보낸다. 클립보드 링크가 있으면 링크가 기본이며, 실제로 파일을 선택하면 링크를 대체한다. 링크 입력으로 전환했을 때 클립보드가 비어 있으면 빈 URL 입력과 클립보드 가져오기를 제공한다. 링크·파일·보관함 자료를 함께 보내지 않으며 전송/취소 버튼은 언제나 하나다. 선택 방법을 바꿔도 모달의 너비·높이를 유지하고 내용 영역 안에서만 스크롤한다. 기기 선택 전에는 전송 입력을 표시하지 않는다. 클립보드의 유효한 HTTP/HTTPS 링크만 제안하며 읽는 것만으로 전송하지 않는다. 다시 선택하거나 페이지로 돌아오면 최신 클립보드를 읽는다. 권한 제한 시 직접 새로고침·붙여넣기를 제공한다. 수동 편집 중인 URL은 자동 갱신으로 덮어쓰지 않는다. 파일 선택은 클립보드 실패와 독립적이다.

전송 버튼 자리에서 취소와 진행률을 표시한다. 모달을 닫는 동작은 진행 중 요청을 취소한다. 완료하면 선택 화면으로 돌아온다. 수신자는 중앙의 흰색 수락/거절 카드로 결정한다. 수락한 탭에서 URL을 바로 열고 파일을 다운로드한다. 정상 완료에는 도착 확인이나 두 번째 열기 팝업이 없다. 새 탭이 차단되거나 준비한 탭을 닫은 경우에만 수동 열기 안내를 제공한다. 재조회와 다른 탭에서는 과거 자료를 자동 실행하지 않는다.

받은 항목과 임시 저장

비로그인 방문자에게 전송 내역을 보여주지 않는다. 로그인한 계정이 수락하고 그 세션이 전달 완료까지 유효한 경우 받은 항목에 기록한다. 로그인 전 받은 자료는 가져오지 않는다. 받은 항목은 날짜별로 묶는다. 자동 열기/다운로드 후 읽음은 기기 접근권과 계정 기록에 함께 반영한다.

오른쪽 보관함 버튼을 누르면 받은 항목을 먼저 표시하고 받은 항목 / 임시 저장을 전환할 수 있다. 임시 저장은 자신이 클립보드 콘텐츠·파일을 담는 공간이다. 먼저 클립보드 저장 / 파일 저장 중 하나를 선택하고 해당 입력만 표시한다. 선택적인 한 줄 제목/메모는 최대 200자이며 원래 만료를 연장하지 않고 수정할 수 있다. 제목 아래 보관 설명은 생략하고 하단 용량 안내와 함께 항목별 최대 7일 보관을 표시한다. 계정 설정에서 이메일 변경 버튼은 숨기고 비밀번호 변경 버튼으로 해당 폼을 열며 모바일에서는 하단 시트로 표시한다. 이메일 주소로 다른 사람에게 보내는 새 요청은 제거했다. Resend는 가입·인증·비밀번호 복구 등 계정 메일에 계속 사용한다.

기기 전송은 새 링크, 새 파일, 로그인한 사용자의 보관함 자료 중에서 보낸다. 보관함은 임시 저장과 받은 항목을 포함한 세 번째 콘텐츠 선택 방법이며 비로그인 화면에서는 숨긴다. 항목 선택은 미리보기만 바꾸고 한 개의 전송 버튼으로 확정한다. 저장한 자료도 대상 기기가 수락한 뒤에 전달한다. 저장된 파일은 서버의 원본을 재사용해 브라우저 재다운로드·재업로드와 중복 물리 저장을 피한다. 원본의 개인 메모는 상대에게 복제하지 않는다. 다른 계정의 자료, 만료·삭제한 원본, 폐기된 발신 계정 세션으로는 보낼 수 없다.

받은 항목과 임시 저장은 각각 저장 시점부터 최대 7일이다. 기존 자료도 마이그레이션 시점부터 최대 7일로 제한하며, 더 가까운 기존 만료는 유지한다. 즐겨찾기로 만료를 우회할 수 없다. 만료 항목과 접근권을 정리하고 마지막 유효한 파일 참조가 사라지면 원본 파일을 제거한다. 새 전송의 수신 기록은 새 저장 시점부터 7일이며 원본 기록의 만료를 연장하지 않는다.

물리 파일은 uploads/originals/user-계정ID 또는 uploads/originals/guest-기기세션ID에 업로드한 사람 기준으로 저장하고 안전한 원래 확장자를 무작위 식별자에 붙인다. 로그인 중 기기 전송은 계정 폴더를 선택하되 기존 기기 세션의 업로드 권한·용량 정책을 유지한다. 수신 보관함은 같은 원본을 참조하며 다른 수신자별로 복제하지 않는다. 다운로드 완료로 폴더를 바꾸지 않으며 completed는 사용하지 않는다. 기존 평면 및 completed 파일은 시작 시 기록된 업로드 소유자 폴더로 이동한다. 계정 정보가 기록되지 않은 과거 파일은 기기 세션 소유자를 사용하며 추정하지 않는다. 진행 중인 파일 읽기는 보호하며 이동 기록으로 중단 후 DB·물리 경로를 복구한다. 사용자 폴더 안에도 수동 삭제 감지와 기존 만료·고아 정리를 적용한다.

주변 발견과 방

주변 기기는 검증된 접속 IP 그룹으로 찾는다. 운영에서는 신뢰할 프록시 경로 검증 후 같은 네트워크 발견을 켠다. 로컬 개발에서는 실제 loopback 접속을 같은 기기의 다른 브라우저로 인식해 자동 발견을 제공한다. 이 방식은 Bluetooth나 물리적 거리 측정이 아니다.

한 기기는 승인 대기를 포함해 한 방에만 속한다. 방 안의 기기는 주변 목록에서 사라지고 그 방에서 승인된 기기끼리만 발견·전송한다. 주변과 방의 목록을 섞지 않는다. 참여하면 초대/참여 모달을 자동으로 닫고, 참여 중에는 새 방 생성/참여 동작을 제공하지 않는다. 상태 아래에는 빨간 방 나가기만 표시한다. 방장이 나가면 방을 닫고 모두 방에서 나온다. 나가기·내보내기·방 종료로 진행 중인 해당 전송도 취소한다.

데이터와 API

기존 요청·묶음·항목·접근권·파일·업로드·인증 구조를 재사용한다. request_receipt_accounts는 기기 수락 시 계정과 인증 세션을 묶고, vault_transfers는 기기 요청과 저장한 원본 접근권을 연결한다. item_access.note는 개인 메모이고 transfer_requests.note는 업로드 완료 시 메모를 저장하기 위한 초안이다. 파일은 원본 ID를 공유하고 접근권은 새 전송별로 생성한다.

  • GET /api/inbox: 로그인 중 수신 기록.
  • GET /api/vault: 자신의 임시 저장 목록, 검색·페이지네이션.
  • GET /api/vault/contents: 직접 저장·받은 항목 중 전송할 수 있는 본인 자료. 보관함 원본 조회는 계정 전환과 겹친 이전 응답을 화면에 반영하지 않는다.
  • POST /api/vault: 링크·텍스트 또는 파일 저장 요청과 선택적 메모. 링크·텍스트는 즉시 확정하고 파일은 기존 인증 업로드 API를 사용한다.
  • PATCH /api/vault/:accessId/note: 개인 메모 수정.
  • POST /api/vault/:accessId/send: 선택한 기기에 기존 자료 전송 요청.
  • 기존 기기 요청의 수락/거절/취소와 파일 다운로드 API는 유지한다. 새 이메일 원격 전송, 영구 즐겨찾기와 익명 자료의 사후 계정 이동은 410으로 거절한다.

마이그레이션 0007–0011은 계정 수신 연결·개인 메모·7일 제한·단일 방 정리·활성 참여의 DB 유일 제약을 추가한다. 기존 다중 참여는 가장 최근 참여 하나만 남기고 방장이 없는 방은 닫는다. 원래 마이그레이션 기록·자료 ID·상대 접근권은 보존한다. 직접 저장의 기존 내부 self 요청은 기존 저장 흐름과 마이그레이션 호환성을 위해 내부 email 모드를 재사용하며, 외부 이메일 전송을 다시 열지는 않는다.

개발은 자동 발견과 반복 테스트용 요청 한도를 사용하고 포트는 OS가 배정한다. 운영의 실제 포트·바인딩·프록시 설정은 배포 때 사용자에게 확인한다.

2026-10-12 업데이트

  • 개인 보관함 기본 한도 2GiB: 임시 저장·받은 항목의 유효한 파일 원본을 계정별로 중복 없이 합산. 받은 파일도 포함하고 삭제·만료한 접근권은 개인 사용량에서 제외한다. 다른 사람의 원본과 저장소를 물리적으로 공유하더라도 계정별 한도는 분리한다.
  • 개인 한도 초과 시 기기 수신·다운로드는 계속하고 해당 파일의 계정 수신 기록만 생략한다. 짧은 알림을 표시한다. 업로드 중인 개인 저장의 예약과 삭제 복원도 한도를 검사한다. 익명 파일 저장 한도는 개인 보관함과 별도이며 익명 화면의 내역은 계속 숨긴다.
  • 파일은 8MiB 조각으로 전송하며 같은 파일 내용 검증·이미 받은 위치·중복 조각·서버 재시작을 처리한다. 자동 재시도 실패 시 기존 단일 버튼이 다시 전송으로 바뀐다. 완료 전후 취소와 접근 범위 검사는 유지한다.
  • 운영 자동 발견은 신뢰한 인접 프록시에서 온 CF-Connecting-IP만 사용하고, 원본 IP와 프록시 진단 결과는 일반 사용자에게 공개하지 않는다. 목록 변화는 접속 이벤트로 갱신하고 대기 중 반복 탐색 문구를 표시하지 않는다. 위치 허용 기반 100m 근처 검색도 제공하며 상세 동작은 NEARBY_DISCOVERY.md를 따른다.
  • PWA 설치: Android 등 설치 이벤트 지원 브라우저는 설치 창, iPhone은 홈 화면 추가 안내. 설치 앱 안에서는 버튼을 숨긴다. Service Worker는 민감한 자료나 API를 캐시하지 않고 오프라인에서는 인터넷 연결 안내만 제공한다.

2026-10-13부터 일반 텍스트도 클립보드 전송·직접 저장·수신 기록·보관함 기기 전송에 포함한다. 세부 판별과 256KiB 제한은 클립보드 전송을 따른다.