Commit Graph

15 Commits

Author SHA1 Message Date
b4dd21e67a feat(packs-lab): chunked resumable upload (offset-based) 추가
기존 single-shot POST /upload는 그대로 유지하고, 5GB+ 안정성을 위한
chunk upload 5-endpoint를 추가했다.

- POST /upload/init — mint-token jti consume + 세션 디렉토리 생성
- PUT /upload/{sid}/chunk?offset=N — offset 매칭 후 .part 파일 append
  · 불일치 시 409 + X-Current-Offset 헤더로 재개 지점 통보
- GET /upload/{sid}/status — 현재 written / expected_size 조회
- POST /upload/{sid}/complete — atomic rename + Supabase INSERT
- DELETE /upload/{sid} — 세션 중단 + 부분파일 정리

auth.py: verify_upload_token_no_consume() 추가 — chunk/complete/abort/status
는 동일 mint-token을 재사용해야 하므로 jti consume 없이 시그니처+만료만 검증.

models.py: InitUploadResponse, ChunkUploadResponse 추가.

세션 state: PACK_BASE_DIR/.uploads/{jti}/meta.json + data.part (파일시스템
영속, 단일 컨테이너 가정).

chunk 크기 상한: PACK_CHUNK_MAX_SIZE env (기본 64MB).

tests: chunk upload 시나리오 8종 — full-flow / offset mismatch / status /
abort / wrong token / incomplete complete / filename collision / host path
저장. 전체 37 테스트 pass.

CLAUDE.md: packs-lab API 표에 chunk 5-endpoint + 사용 패턴 보강.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 02:36:20 +09:00
448dbd5f48 feat(packs-lab): DSM 호출 retry/backoff + 업로드 cleanup 보강
- dsm_client.py: _request_with_retry()로 5xx·transport·timeout만 지수백오프
  재시도 (DSM_MAX_RETRIES, DSM_BACKOFF_SEC env). DSM error code 응답 본문 로깅.
- routes.py: upload 핸들러를 try/finally로 감싸 부분파일 정리 보장, Supabase
  INSERT 호출 자체에 try/except 추가해 네트워크 예외도 cleanup.
- test_dsm_client.py: retry 시나리오 4종 추가 (5xx→성공/소진/transport
  error/4xx no-retry). 전체 29 테스트 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 02:31:39 +09:00
1d4bff31c4 feat(packs-lab): DSM_VERIFY_SSL env — LAN IP + self-signed cert 환경 대응
운영 NAS에서 DSM_HOST=https://192.168.x.x:5001 같은 LAN IP 사용 시
DSM의 self-signed 인증서가 IP 주소에 매칭되지 않아 SSL 검증 실패
(SSL: CERTIFICATE_VERIFY_FAILED — IP address mismatch).

LAN 내부 통신이라 verify=False 허용 가능. 환경변수로 토글:
- DSM_VERIFY_SSL=true (default) — 도메인 + 정상 cert 환경
- DSM_VERIFY_SSL=false — LAN IP + self-signed 환경

dsm_client.py가 환경변수 읽어 httpx.AsyncClient(verify=...)에 전달.
docker-compose.yml + .env.example + CLAUDE.md에 신규 env 명시.
회귀 25/25 passing.
2026-05-11 03:31:15 +09:00
aec0fdcd31 fix(packs-lab): tier 디렉토리 제거(평면 구조) + deployer SERVICES에 packs-lab 추가
문제 1: deploy-nas.sh의 SERVICES 화이트리스트에 packs-lab이 빠져 있어
NAS 운영 디렉토리에 소스 sync가 안 됐고 docker compose가 packs-lab을
빌드 못해 컨테이너가 안 떠 있었다.

문제 2: routes.py가 PACK_BASE_DIR/{tier}/{filename} 트리 구조로 저장 →
사용자 요청에 따라 평면 구조(PACK_BASE_DIR/{filename})로 변경. tier 구분은
filename 규칙(prefix 등)으로 admin이 관리.

- scripts/deploy-nas.sh: SERVICES에 packs-lab 추가 (10개 → 11개)
- routes.py: tier 디렉토리 제거 (target = PACK_BASE_DIR / filename, host_path = PACK_HOST_DIR / filename)
- tests: tier 분기 사용처 평면 구조로 보정 (size_mismatch / host_path_check)
- 25/25 passing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:54:25 +09:00
f1f1dc98a6 fix(packs-lab): PACK_HOST_DIR 도입 — sign-link 시 DSM이 NAS 호스트경로 받도록
이전: upload가 컨테이너 경로(/app/data/packs/...)를 Supabase에 저장 →
sign-link 시 그 경로를 DSM에 전달 → DSM은 NAS 호스트 절대경로
(/volume1/.../media/packs/...) 기준이라 파일을 찾지 못함.

수정:
- routes.py: PACK_HOST_DIR 신규 (env, fallback=PACK_BASE_DIR)
  - upload 시 host_path = PACK_HOST_DIR/{tier}/{filename}을 Supabase에 INSERT
  - sign-link 시 PACK_HOST_DIR 기준 경로 검증
- docker-compose: PACK_HOST_DIR env 주입 (default=PACK_DATA_PATH)
- .env.example + CLAUDE.md: 환경변수 의미 분리 명시
- tests: 호스트경로 저장 검증 신규 (test_upload_stores_host_path_not_container_path)
- 25/25 passing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:47:26 +09:00
5844567048 fix(packs-lab): PACK_BASE_DIR을 환경변수로 — 컨테이너 마운트 경로와 routes 정합성 확보
이전 docker-compose는 컨테이너 내부 /app/data/packs로 마운트하지만 routes.py는
/volume1/docker/webpage/media/packs를 하드코딩하고 있어 mismatch였다.

- routes.py: PACK_BASE_DIR = Path(os.getenv("PACK_BASE_DIR", "/app/data/packs"))
- docker-compose: PACK_BASE_DIR env 추가 + volume 마운트가 같은 경로 사용
- .env.example: PACK_BASE_DIR 신규 명시 (마운트 경로와 반드시 일치 안내)
2026-05-06 01:40:07 +09:00
ff4ef299ad feat(packs-lab): Supabase pack_files DDL + 활성/삭제 인덱스 2026-05-06 01:35:19 +09:00
5ebcbae8b5 docs(packs-lab): routes 모듈 docstring 정리 (mint-token 추가, DSM 자동 만료 명시) 2026-05-06 01:34:47 +09:00
1cd3cf8830 test(packs-lab): DSM client mock 테스트 (login/share/logout 순서)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:33:11 +09:00
c18fd8e52b test(packs-lab): upload size/replay + delete soft-delete + list filter 회귀 테스트
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:30:46 +09:00
dc482b32e4 feat(packs-lab): POST /api/packs/admin/mint-token 라우트 + 통합 테스트
MintTokenRequest/Response 스키마 추가, mint_token 라우트 구현 (HMAC 인증 + 확장자 검증 + JTI 발급), 테스트 3건 추가.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:27:43 +09:00
ef026e7ac6 test(packs-lab): conftest로 HMAC secret 통일
모든 테스트에서 BACKEND_HMAC_SECRET 환경변수와 auth._SECRET 모듈 캐시를
동일한 값으로 설정하는 autouse fixture 추가.
기존 test_auth.py / test_routes.py와 동일한 secret 값 사용.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:24:17 +09:00
7a9690526a test(packs-lab): routes 통합 테스트 (DSM·supabase mock) 2026-05-02 08:55:26 +09:00
7a7e3d1ce0 fix(packs-lab): 누락된 A1-A3 파일 복구 (Dockerfile + auth + DSM client + tests)
Tasks A1-A3 의 파일이 working tree에 있었으나 git에 stage되지 않은 상태에서
A4 commit이 진행되어 routes.py 의 import (auth, dsm_client)가 깨진 상태였음.
복구: 8 files 일괄 commit.

- packs-lab/Dockerfile
- packs-lab/app/__init__.py
- packs-lab/app/requirements.txt
- packs-lab/app/auth.py (HMAC verify_request_hmac + verify_upload_token)
- packs-lab/app/dsm_client.py (DSM 7.x Sharing.create wrapper)
- packs-lab/tests/{__init__.py, test_auth.py}
- packs-lab/pytest.ini
2026-05-02 08:53:26 +09:00
eb547a0367 feat(packs-lab): 4 라우트 — sign-link, upload, list, delete (HMAC + supabase) 2026-05-02 08:52:24 +09:00