hop.

기기 사이를 가볍게. 가입 없이 접속한 브라우저 사이에서 수락 후 자료를 전달하는 서비스입니다.

현재 Phase 1·2 검증 완료 · Phase 3 구현 진행 중입니다. 파일 전송은 구현되어 있습니다. 로그인 수신 기록·7일 보관함은 구현되어 있으며 Resend API 어댑터의 실제 메일 수신 검증이 남아 있습니다. 관리자·PWA는 후속 단계입니다. 전체 설계는 구현 계획, 개발 기준은 SPEC.md를 참고하세요.

로컬 개발

Node.js 22.12 이상과 npm을 사용합니다.

npm ci
npm run build -w @hop/shared
npm run dev

웹과 API 모두 OS가 빈 임시 포트를 배정합니다. 프로젝트 루트 .env를 읽습니다. 개발 DB·파일은 기본 .data/를 사용하며 Docker의 /data/ 설정을 그대로 사용하지 않습니다. 출력된 개발 화면 주소를 열어 주세요. 서버 코드 변경은 자동으로 다시 시작하며 실행 중에는 배정된 포트를 유지합니다. 고정 샘플 포트나 기존 서비스 포트를 사용하지 않습니다. 데이터는 .data/hop.sqlite에 저장합니다. 동일 브라우저의 탭은 하나의 기기이므로 다른 기기를 테스트하려면 다른 브라우저·프로필·시크릿 창을 사용하세요.

검증

npm run typecheck
npm run build
npm test

API 테스트는 격리된 실제 SQLite DB와 임시 로컬 포트의 Socket.IO를 사용합니다. 테스트 환경이 로컬 소켓 연결을 제한하면 권한이 필요할 수 있습니다. 운영 프록시와 실기기 확인을 자동 테스트로 대신했다고 주장하지 않습니다.

Docker 배포 준비

유그린 NAS에서 Docker 앱 버튼으로 배포하는 순서는 deploy.md를 따라 진행하세요. 현재 배포 경로는 Cloudflare Tunnel → 기존 NPM(8080) → NAS의 hop.(50189)입니다.

.env.example을 .env로 복사하고 비밀값을 설정합니다. SESSION_SECRET과 DISCOVERY_SECRET은 서로 다른 32자 이상의 무작위 비밀값이어야 합니다. 예를 들어 openssl rand -hex 32로 각각 생성합니다. Git에 실제 환경 파일·DB·파일을 넣지 않습니다.

이번 NAS 배포는 사용자가 지정한 50189를 호스트·컨테이너 포트로 사용합니다. scripts/configure-nas.sh가 실제 NAS 내부 IP를 물어보고 운영 .env와 배포 YAML을 준비합니다. 다른 환경에서는 충돌 없는 포트·바인딩 IP·프록시 경로를 따로 확인하세요. Compose는 필수 값이 비어 있으면 실행을 거절합니다. .env는 Node 서버 직접 실행 시 자동 로드되지 않으며 Compose 또는 실행 환경이 주입합니다.

docker compose config
docker compose up -d --build

앱 시작 시 버전 관리된 Drizzle 마이그레이션을 적용하며 실패하면 시작하지 않습니다. DB와 업로드 볼륨은 재배포·재시작 후 유지됩니다. docker compose down -v는 데이터를 삭제하므로 사용하지 마세요.

Nginx Proxy Manager에는 실제 컨테이너/호스트 경로의 포트를 지정하고 HTTPS·WebSocket 지원을 켭니다. Secure 쿠키 때문에 운영 환경에서는 HTTPS가 필수입니다. 요청·연결 타임아웃과 업로드 제한은 Phase 2에서 문서화하고 실제 경로에서 검증합니다. 앱의 파일 상한은 중간 프록시·Cloudflare 상한을 보장하지 않습니다.

발견과 QR·코드 연결

같은 네트워크 탐색은 기본 비활성입니다. TRUSTED_PROXY_CIDRS는 실제로 앱에 연결하는 검증된 프록시 IP/CIDR만 허용합니다. 임의 전달 헤더를 신뢰하지 않습니다. 검증된 클라이언트 IP를 얻지 못하면 네트워크 탐색을 하지 않습니다. 공인 IP가 정확히 같은 경우만 후보로 표시하고 IPv6 /64 통합은 하지 않습니다. 같은 공인 IP는 동일 Wi-Fi나 실제 근접의 증명이 아닙니다.

QR·8자리 코드는 기본 10분의 임시 공간 초대입니다. 최대 10대, 선택적 참여 승인, 내보내기와 공간 닫기를 지원합니다. 공간 참여와 자료 전송 수락은 별개입니다. QR 초대 토큰은 URL fragment에 넣어 서버 요청·리퍼러로 전달하지 않으며 참여 후 주소에서 지웁니다.

익명 자료

비로그인 화면에는 전송 내역을 표시하지 않습니다. 수락 후 링크는 새 탭으로 열고 파일은 다운로드합니다. 익명 기기 세션은 기본 30일이며 저장한 자료는 최대 7일입니다. 쿠키 삭제·만료·초기화 시 이전 익명 접근권은 복구할 수 없습니다. 로그인 전 수신 자료를 계정으로 가져오지 않습니다. 기기 세션 정리가 필요하면 브라우저의 사이트 데이터를 삭제합니다. 기기 이름은 인증된 신원이 아니며 전송은 서버를 경유합니다. E2EE나 P2P 전송을 제공한다고 안내하지 않습니다.

업데이트와 백업

업데이트 전 앱을 정지하고 DB 볼륨(관련 WAL·SHM 포함)과 업로드 볼륨을 같은 시점에 백업합니다. SQLite 파일만 실행 중에 임의 복사하지 마세요. 복원은 별도 볼륨에서 DB integrity check와 실제 자료 접근을 확인한 뒤 적용합니다. 실제 Docker 백업·복원 검증은 Phase 5에서 수행합니다.

파일당 기본 2GiB, 익명 주체당 2GiB, 전체 익명 20GiB 제한과 최소 5GiB 여유 공간을 적용합니다. MB/KB 환경변수는 MiB/KiB 기준입니다. 파일은 수락 후 스트리밍 저장하고 중단 시 임시 파일·예약을 회수합니다. 초기에는 업로드 재개나 백그라운드 완료를 보장하지 않습니다.

개발 환경의 QR

기본 개발 URL은 127.0.0.1입니다. 이 URL을 휴대폰에서 열면 휴대폰 자신을 가리키므로 PC 개발 서버에 접속할 수 없습니다. 같은 PC의 다른 브라우저·시크릿 창에서는 코드를 입력해 연결할 수 있습니다. 휴대폰 검증을 시작할 때 사용할 LAN 접속 주소·포트·바인딩 범위를 사용자에게 확인합니다. HTTPS 운영 배포에서는 공개 서비스 주소로 QR을 생성합니다. 개발 HTTP 환경에서는 플랫폼에 따라 클립보드 등 보안 컨텍스트 API가 제한될 수 있습니다.

이메일 발송

2026-10-08 사용자 지침에 따라 명세의 SMTP 대신 기존 Resend 연동을 사용합니다. 발신 주소는 hello@noname.company입니다. Resend HTTPS API 발송 어댑터를 연결했습니다. 루트 .env의 RESEND_API_KEY와 MAIL_FROM을 서버에서 읽으며 API 키는 브라우저로 전달하지 않습니다. 공개 가입은 기본 닫혀 있으며, REGISTRATION_MODE=open으로 시작하려면 사용 가능한 메일 어댑터가 필요합니다. API 키는 Git에 저장하지 않습니다.

계정 메일 토큰은 일회용·해시 저장이며 링크 fragment를 사용합니다. 인증 전 계정 업로드·원격 전송·수락을 금지합니다. 이메일 정규화는 양끝 공백 제거와 도메인 소문자화이며 로컬 파트 대소문자·점·별칭은 보존합니다. ‘내 계정에 저장’은 기존 익명 접근권을 제거하고 계정 보관함으로 이동하며 원래 만료와 상대 접근권을 유지합니다.

최초 관리자 초기화는 SETUP_TOKEN(32자 이상 무작위 비밀값)과 빈 사용자 DB 조건으로만 가능합니다. /api/auth/setup도 이메일 인증을 거치며, 실제 메일 수신 검증 후 실행 절차를 완성합니다.

기술 참고: Fastify 프록시 설정, Drizzle SQLite, Tailwind Vite.

현재 전송 UX

파일·링크 통합 수정안을 우선합니다. 일반 텍스트 전송과 유형 탭은 제거했습니다. 기기를 누르면 클립보드 URL을 제안하며, 권한 거부나 일반 텍스트는 무시하고 파일 선택을 유지합니다. 링크 직접 붙여넣기도 가능합니다. 읽기만으로 전송하지 않으며 수락 후에만 전달합니다. 수신과 완료 카드는 뷰포트 상단에 표시됩니다. 기본 테마는 검정이며 라이트·시스템 전환을 유지합니다.

개발 테스트 계정

node --import tsx scripts/seed-test-accounts.mjs로 개발 DB에 인증된 일반 사용자 test1@hop.test, test2@hop.test를 준비합니다. 비밀번호는 둘 다 1234입니다. 메일을 보내지 않으며 운영 환경에서는 실행을 거절합니다. 같은 이름의 테스트 계정은 비밀번호만 재설정하고 다른 기존 계정은 변경하지 않습니다.

개발·테스트 환경은 1자 이상 비밀번호를 허용합니다. 운영 환경(NODE_ENV=production)은 기존 12자 이상 규칙을 유지하며 가입·재설정 화면도 서버가 제공한 최소 길이를 적용합니다.

현재 전송·보관함 흐름

최신 동작 기준은 TEMPORARY_VAULT.md입니다. 중앙에서 기기를 고른 뒤 PC 모달·모바일 하단 시트로 링크·파일·임시 저장 자료를 보냅니다. 로그인 중 받은 자료는 보관함의 받은 항목에 날짜별로 남고, 직접 담은 자료는 임시 저장에서 한 줄 메모와 함께 관리합니다. 모든 자료는 최대 7일입니다. 저장 종류는 먼저 링크/파일 중 하나를 선택합니다. 이메일 원격 전송과 영구 즐겨찾기는 제거했습니다.

개발 실행은 같은 PC의 다른 브라우저를 자동 발견하고 반복 검증용 요청 한도를 사용합니다. QR 방에 들어가면 방 안의 기기만 보이며 한 방만 참여할 수 있습니다. 방장 나가기는 방 전체를 닫습니다. 운영 발견은 실제 프록시 경로를 검증한 후 켭니다.

npm run test:e2e:layout은 실제 12개 기기 연결과 4/3/2열, 선택 전 입력 없음, 중앙 모달/하단 시트 및 방 격리를 검증합니다.

Description
No description provided
Readme 3 MiB
Languages
JavaScript 52.2%
TypeScript 24%
Vue 15.3%
CSS 7.4%
Shell 0.9%
Other 0.1%