24 KiB
title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, branch, parent_branch, related_projects, tags, created, target_merge, status_label, contract_packet_sha256
| title | source_type | status | id | kind | project | work_item | inherits | refines | overrides | depends_on | contract_packet | branch | parent_branch | related_projects | tags | created | target_merge | status_label | contract_packet_sha256 | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| branch / feature-file-resource-handling-contract | branch-note | raw | BR-CA-SKELETON-OPERATIONAL-CONTRACT-023 | project-work-item | ca-skeleton-operational-contract | WI-CA-SKELETON-OPERATIONAL-CONTRACT-023 |
|
1 | feature-file-resource-handling-contract |
|
|
2026-05-22 | in-progress | 7db5c6a4eb77af61706b5f4688cf721f786789638595dca733d334c5dca3d3c0 |
branch: feature-file-resource-handling-contract
Layer:
raw/branch-notes/— file/resource 처리 실패 기준을 정의합니다.
[!note] 개정 예정 고지 (2026-07-28) 본 branch 는 owner 를 유지하되 내용을 코드 사실에 맞춰 개정한다. 근거:
docs/superpowers/specs/2026-07-28-ca-skeleton-production-capability-feature-decomposition-design.md§5.3.
- 개정 사유: 전체 파일 버퍼링 + 비원자 덮어쓰기. staged publish(임시 파일 → fsync → atomic rename → 디렉터리 fsync) 프로토콜과 quota·retention·CSV 수식 주입 방어를 재판정한다. object storage 스트리밍은 신규 branch 로 분리.
- 참조 설계: ca-tmpl
docs/superpowers/specs/2026-07-26-fileserver-production-capability-design.md§11·§12·§13 (등급internal-design-doc— 공식 문서 아님)
부모 (필수)
- Parent project (canonical SSOT): raw/project-notes/ca-skeleton-operational-contract
ca-skeleton 은 별도 root branch 없이 project-note 가 SSOT 역할. 본 feature branch 는 project-note 의 운영 계약 중 해당 영역 (§<관련 섹션>) 의 결정/근거/금지 사항을 정제한다.
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: file size·type·storage boundary test가 통과한다
상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-MODULE-LAYOUT-001@1 |
Gradle multi-module에서 domain-core·application-core·adapter-*·shared-contract·app-bootstrap·sample-portfolio 책임을 분리한다 | file/resource 처리의 application·adapter 책임 경계에 적용 | raw/project-notes/ca-skeleton-operational-contract |
브랜치 지역 결정
기존 branch-local 결정은 아래
## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
묶음
- raw/company-tech-blogs/file-clamav-icap-gateway-scan
- raw/official-docs/file-s3-presigned-url-upload
- raw/official-docs/file-tus-resumable-upload-protocol
- raw/official-docs/iana-media-types-registry
- raw/official-docs/jdk-files-createtempfile
- raw/official-docs/nginx-client-max-body-size
- raw/official-docs/owasp-file-upload-cheat-sheet
- raw/official-docs/owasp-path-traversal
- raw/official-docs/spring-boot-multipart-reference
- raw/official-docs/spring-mvc-async-streaming
- raw/official-docs/spring-streaming-response-body
본 feature branch 는 leaf — 자식 자료 없음. Phase C2 실 코드 작성 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.
오류 기록 (본 feature 작업 중 발생)
- (없음 — 현재 documented-only 단계)
면접 준비 (이 작업에서 나올 수 있는 면접 질문)
- (없음 — Phase C2 실 구현 단계에 누적)
목표
multipart 실패만으로는 파일 처리 기준이 부족합니다. upload size, temp file cleanup, streaming failure, content type sniffing, path traversal 방지를 skeleton 기준에 포함해야 합니다.
- 이슈:
- PR:
범위
포함 범위
- upload size limit.
- multipart parse failure.
- temp file cleanup.
- download streaming failure.
- content type sniffing 금지.
- path traversal 방지.
- resource exhaustion 분류.
제외 범위
- 실제 object storage adapter 구현.
- antivirus scan 구현.
- CDN/download product policy.
TODO
TODO drained 2026-05-22 — 결정은 아래 "결정 사항" / "Decisionized Work Items" / "테스트 계약" 참조. upload size/multipart parse/temp cleanup/streaming/content-type allowlist/path traversal/resource exhaustion/antivirus 위치 모두 결정 라인 또는 표 row로 반영됨. 잔존 TODO 없음.
Work Item Contract
각 TODO는 아래 판정 단위로 재작성되어야 canonical 승급 가능합니다. TODO가 단순히 기준 작성으로 남아 있으면 이 branch는 완료로 보지 않습니다.
| field | required | rule |
|---|---|---|
| Decision | yes | 구현자가 선택해야 하는 기본값 |
| Allowed | yes | 허용되는 예외와 조건 |
| Forbidden | yes | 절대 금지되는 구현/문서 상태 |
| Required registry update | conditional | error/env/header/log/metric/capability 변경 시 필수 |
| Required contract test | yes | 계약 위반 시 실패해야 하는 테스트 |
| Failure condition | yes | review/build에서 실패로 판정할 상태 |
| Canonical extraction target | yes | wiki/projects 승급 위치 |
진행 중 메모
- file/resource handling은 API contract와 runtime lifecycle 양쪽에 걸칩니다.
결정 사항 (decisions)
- 2026-05-22: file/resource handling을 별도 운영 표면으로 분리.
- 2026-05-22: antivirus/file scanning은 기본 off. 활성화 위치는 gateway, async worker, app inline 중 하나로 명시해야 하며 미정이면 업로드 feature 승급 불가.
- 2026-05-22: upload size limit 기본값은 10MB, file sample은 core v1에 포함하지 않음.
- 2026-05-22: size limit enforcement layer SSOT = Spring
spring.servlet.multipart.max-file-size10MB + global request size 12MB. gateway/WAF는 보조(20MB hard limit). Spring 단의 enforcement가 실패 시 envelope 응답 보장. - 2026-05-22: 3계층 분리는 의도된 defense-in-depth: gateway 20MB는 raw 413 직격 차단 (envelope 우회), global 12MB는 multipart 외 raw body 한도, Spring 10MB는 multipart 단일 file 한도. 모든 한도 위반은 Spring 단에서 분류되어 envelope 응답으로 변환.
- 2026-05-22: temp file cleanup trigger = (1) success/failure on close (try-with-resources), (2) startup sweeper for orphaned files older than 1h, (3) JVM shutdown hook은 backup. file >1h not closed → orphan.
- 2026-05-22: allowed content-type allowlist starting set = image/jpeg, image/png, image/webp, application/pdf, text/csv, application/zip. 추가는 endpoint별 registry 등록.
- 2026-05-22: streaming download backpressure = response timeout 60s, max stream 100MB. 초과 시 truncate + ERROR log.
- 2026-05-22: file storage abstraction은 outbound = object store call이 EXTERNAL_OUTBOUND_ALLOWED capability 요구.
- 2026-05-22: antivirus default = scan position = "gateway" (외부 upload-가능 endpoint), in-app 검증은 disabled. 활성화 시 별도 worker로 분리.
결정-근거 매핑
각 결정이 어떤 raw source claim 으로 뒷받침되는지 명시. Company-tech-blog / vendor blog 인용은 사례 (
company-case-study) 로만 사용, 공식 best practice 단정 금지.
| Decision ID | Decision | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|
| D1 | file/resource handling 을 별도 운영 표면으로 분리 | UNSUPPORTED_DECISION — 내부 조직/스코프 결정 | internal-only |
다른 branch (lifecycle/outbound) 와 책임 경계 lint 필요 |
| D2 | antivirus/file scanning default = off, 활성화 위치는 gateway/worker/app 중 1개 명시 강제 | raw/company-tech-blogs/file-clamav-icap-gateway-scan.md#CLAMAV-ICAP-C1, raw/company-tech-blogs/file-clamav-icap-gateway-scan.md#CLAMAV-ICAP-C2 (ICAP = official-standard strength) |
official-standard + official-vendor-doc |
gateway 위치 default 권고는 company-case-study 영역 — 공식 best practice 단정 금지 |
| D3 | upload size limit default = 10MB, file sample core v1 미포함 | 메커니즘 SUPPORTED: raw/official-docs/spring-boot-multipart-reference.md#SB-MULTIPART-C1 (Servlet 5 Part API 채택, official-vendor-doc), raw/official-docs/spring-boot-multipart-reference.md#SB-MULTIPART-C2 (Spring Boot default per-file 1MB / per-request 10MB, official-vendor-doc). 정량값 UNSUPPORTED_DECISION: per-file 10MB default 는 Spring Boot upstream default (1MB) 와 다르며 ca-tmpl 자체 결정 — 외부 권고 부재 |
official-vendor-doc (mechanism only) |
10MB 정량값은 ca-tmpl 자체 결정 — endpoint registry override 정책으로 보완 필요. 'file sample core v1 미포함' 은 internal scope 결정 (UNSUPPORTED) |
| D4 | size limit enforcement SSOT = Spring (multipart 10MB + global request 12MB), gateway/WAF 는 보조 (20MB hard) | 메커니즘 SUPPORTED: raw/official-docs/spring-boot-multipart-reference.md#SB-MULTIPART-C3 (MultipartProperties 가 spring.servlet.multipart prefix 로 max size / 저장 위치 / disk flush threshold override 가능, official-vendor-doc), raw/official-docs/spring-boot-multipart-reference.md#SB-MULTIPART-C4 (max-file-size=-1 로 unlimited 설정 가능, official-vendor-doc), raw/official-docs/nginx-client-max-body-size.md#NGINX-CMB-C1 (client_max_body_size size; syntax, official-vendor-doc), raw/official-docs/nginx-client-max-body-size.md#NGINX-CMB-C4 (초과 시 HTTP 413 응답, official-vendor-doc). 정량값 UNSUPPORTED_DECISION: 12MB global / 20MB gateway 정량값은 ca-tmpl 자체 결정 — 외부 권고 부재 |
official-vendor-doc (mechanism only) |
12MB / 20MB 정량값은 ca-tmpl 추론. nginx default 는 1MB (NGINX-CMB-C2) 임을 명시 — 20MB 는 의도적 override |
| D5 | 3계층 분리 (gateway 20MB / global 12MB / Spring 10MB) 는 defense-in-depth | SUPPORTED: raw/official-docs/owasp-file-upload-cheat-sheet.md#OWASP-FUP-C1 (extension allowlist 만으로는 불충분 → 다층 검증 필요, official-reference), raw/official-docs/owasp-file-upload-cheat-sheet.md#OWASP-FUP-C2 (Content-Type 헤더 신뢰 불가 → server-side 검증 별도 필요, official-reference), raw/official-docs/owasp-file-upload-cheat-sheet.md#OWASP-FUP-C3 (UUID/GUID 랜덤 파일명 essential, official-reference) |
official-reference |
OWASP cheatsheet 는 reference (표준 아님). 3계층 size 분리 자체는 size 검증의 defense-in-depth — OWASP 가 직접 '3-layer size limit' 권고하는 raw 인용은 없음, 다층 검증 원칙 일반화 |
| D6 | temp file cleanup 3 trigger: try-with-resources + startup sweeper (>1h orphan) + JVM shutdown hook (backup) | 메커니즘 SUPPORTED: raw/official-docs/jdk-files-createtempfile.md#JDK-TEMPFILE-C6 (DELETE_ON_CLOSE 옵션으로 close 시 자동 삭제, official-vendor-doc), raw/official-docs/jdk-files-createtempfile.md#JDK-TEMPFILE-C7 (shutdown-hook 또는 File.deleteOnExit() 로 자동 삭제 가능, official-vendor-doc). 정량값 UNSUPPORTED_DECISION: 1h orphan threshold 는 ca-tmpl 자체 결정 — JDK doc 은 threshold 정량값 권고 없음 |
official-vendor-doc (mechanism only) |
1h orphan threshold 외부 권고 부재. JDK-TEMPFILE-C7 의 deleteOnExit() 는 SIGKILL 등 abnormal termination 보장 없음 — startup sweeper 가 그 gap 메움 |
| D7 | content-type allowlist starting set = image/jpeg, image/png, image/webp, application/pdf, text/csv, application/zip | SUPPORTED: raw/official-docs/iana-media-types-registry.md#IANA-MEDIA-C1 (Media Types 의 assignment/listing 은 IANA 단일 registry, official-standard), raw/official-docs/iana-media-types-registry.md#IANA-MEDIA-C5 (top-level types: application, image, text, ... — allowlist 6종이 모두 IANA top-level 내, official-standard), raw/official-docs/owasp-file-upload-cheat-sheet.md#OWASP-FUP-C5 (webroot 밖 저장 + administrative access only, official-reference) |
official-standard + official-reference |
6종 starting set 선정 자체는 ca-tmpl 도메인 결정 — IANA 는 registry 권위만, endpoint 별 권고 없음. 추가 endpoint registry 등록 정책으로 보완 |
| D8 | streaming download = response timeout 60s + max stream 100MB, 초과 시 truncate + ERROR log | 메커니즘 SUPPORTED: raw/official-docs/spring-streaming-response-body.md#SPRING-STREAM-RB-C3 (StreamingResponseBody 의 명시된 use case = file download, official-vendor-doc), raw/official-docs/spring-streaming-response-body.md#SPRING-STREAM-RB-C4 (ResponseEntity body 로 사용 가능 — status/header 커스터마이즈, official-vendor-doc). 정량값 UNSUPPORTED_DECISION: 60s timeout / 100MB max stream / truncate 정책 모두 ca-tmpl 자체 결정 — Spring doc 은 정량값 권고 없음 |
official-vendor-doc (mechanism only) |
timeout 60s 는 Spring default 의존 (SPRING-STREAM-RB-C8 — 컨테이너 의존) 과 다른 명시값. truncate 동작 자체는 Spring 가 보장하지 않음 — 자체 구현 필요 |
| D9 | file storage abstraction = outbound, object store call 은 EXTERNAL_OUTBOUND_ALLOWED capability 요구 | UNSUPPORTED_DECISION — 내부 capability 모델 결정 | internal-only |
capability 모델의 lint 필요 |
| Path-traversal claim | filename 입력 검증 = normalized storage key only + opaque key (raw path passthrough 금지) — Decisionized Work Items 의 path traversal row 근거 |
SUPPORTED: raw/official-docs/owasp-path-traversal.md#OWASP-PT-C1 (path traversal = web root 밖 파일/디렉토리 접근 공격 정의, official-reference), raw/official-docs/owasp-path-traversal.md#OWASP-PT-C2 (공격 벡터: ../ sequence + variation + absolute path, official-reference), raw/official-docs/owasp-path-traversal.md#OWASP-PT-C3 (방어 원칙: "known good only" allowlist, sanitize 금지, official-reference) |
official-reference |
OWASP community wiki 는 reference (표준 아님). URL encoding (OWASP-PT-C4) / null byte (OWASP-PT-C5) variation 도 별도 검증 필요 — opaque key 정책이 모든 variation 차단 가정은 별도 contract test 필요 |
| D10 | antivirus default scan position = gateway, in-app disabled, 활성화 시 별도 worker 분리 | raw/company-tech-blogs/file-clamav-icap-gateway-scan.md#CLAMAV-ICAP-C2 (ICAP official-standard), raw/company-tech-blogs/file-clamav-icap-gateway-scan.md#CLAMAV-ICAP-C3 (ICAP virus scan use case, official-standard), raw/company-tech-blogs/file-clamav-icap-gateway-scan.md#CLAMAV-ICAP-C1 (ClamAV daemon model, official-vendor-doc) |
official-standard + official-vendor-doc |
ICAP 가 HTTPS E2E TLS 환경에서 적용 어려움 (raw 메모에 명시) — 본 결정의 제약. gateway 가 default 라는 정량 권고는 ca-tmpl 자체 추론 |
| D11 | 대안 1 (Direct S3 presigned URL upload) — app via 3-layer 우회 가능하나 antivirus 위치 분리 필요 | raw/official-docs/file-s3-presigned-url-upload.md#FS3-PRE-C1, raw/official-docs/file-s3-presigned-url-upload.md#FS3-PRE-C2, raw/official-docs/file-s3-presigned-url-upload.md#FS3-PRE-C4, raw/official-docs/file-s3-presigned-url-upload.md#FS3-PRE-C5 |
official-vendor-doc |
post-upload async scan + quarantine bucket 패턴 별도 설계 필요 (raw 메모 참조) |
| D12 | 대안 2 (tus.io resumable upload) — 100MB+ 영상 적합하나 "1h orphan cleanup" 충돌 위험 | raw/official-docs/file-tus-resumable-upload-protocol.md#TUS-RUP-C1, raw/official-docs/file-tus-resumable-upload-protocol.md#TUS-RUP-C3, raw/official-docs/file-tus-resumable-upload-protocol.md#TUS-RUP-C4, raw/official-docs/file-tus-resumable-upload-protocol.md#TUS-RUP-C5 |
official-standard |
tus session timeout 과 orphan threshold 분리 필요 — 채택 시 D6 의 1h threshold 수정 |
검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| Spring 10MB + global 12MB + gateway 20MB 3계층이 ca-tmpl 트래픽 프로파일에 적합 | 정량값 외부 권고 부재 (D3/D4/D5) | k6 부하테스트로 413 응답 비율 + Spring multipart parser 동작 확인 | planned |
| Temp file cleanup 3 trigger 가 모두 정확히 동작 (1h orphan 정확 식별) | JDK 공식 doc 인용 부재 (D6) | TempFileCleanupContractTest 로 정상/예외/timeout 3 경로 cleanup 확인 + startup sweeper orphan(>1h) 삭제 verify |
planned |
| Antivirus gateway 위치가 ca-tmpl 의 HTTPS termination 정책과 호환 | ICAP 가 HTTPS E2E TLS 환경에서 적용 어려움 (raw 메모) | gateway HTTPS termination 정책 확인 + ICAP server 통합 PoC | needs-confirmation |
| ClamAV signature DB 갱신 주기 + 운영 책임 주체 (gateway team vs app team) | raw 에 명시 없음 (Usage Boundary 참조) | 운영 협약 문서 작성 + signature update cron 확인 | needs-confirmation |
| Direct S3 대안 채택 시 EXTERNAL_OUTBOUND_ALLOWED capability 매핑 | raw FS3-PRE-* 는 S3 메커니즘만 보장, ca-tmpl 자체 capability 모델과의 매핑은 별도 |
capability 모델 contract test + signing 호출 경로 추적 | planned |
| tus 채택 시 session timeout 과 orphan threshold 가 정상 case 를 삭제하지 않음 | TUS-RUP-C5 는 max-size 만 정의, session lifetime 침묵 |
tus session 정책 + ca-tmpl orphan threshold 분리 contract test | planned |
| Content-type allowlist 6개 starting set 이 ca-tmpl 도메인 endpoint 별로 충분 | IANA registry 또는 endpoint 별 권고 부재 (D7) | endpoint별 use case 인터뷰 + allowlist 누락 endpoint inventory | needs-confirmation |
| Streaming download 100MB / 60s timeout 이 적합 | 정량값 외부 권고 부재 (D8) | 실제 파일 크기 분포 측정 + truncate 발생률 확인 | planned |
| Path traversal opaque key 정책이 모든 upload 경로 (legacy 포함) 적용 | raw 인용 부재 — OWASP 또는 Spring Security 공식 doc 권고 | traversal test + storage layer code review |
planned |
Decisionized Work Items
| item | Decision | Allowed | Forbidden | Required test |
|---|---|---|---|---|
| upload size | 10MB default | endpoint override with registry | unlimited upload | oversized upload test |
| scanning | off by default, owner required if enabled | gateway/worker/app inline | "somewhere scans it" assumption | scan owner checklist |
| path traversal | normalized storage key only | object-store opaque key | raw path passthrough | traversal test |
| temp cleanup | bounded temp dir + cleanup on failure | streaming direct to storage | orphan temp files | cleanup test |
구현 가이드
현재 documented-only 단계이며 구현 위치·클래스·메커니즘 anchor는 아직 고정되지 않았다. 구현 결정은 기존 ## Decision Evidence Map / 결정-근거 매핑의 D-row를 변경하지 않고 후속 구현 단계에서 연결한다.
엣지·실패·의존
- 실패·엣지 경로: 아래
## 테스트 계약의 oversized upload, temp cleanup, path traversal, streaming failure, antivirus 위치 검사를 따른다. - 다른 계약 의존: API contract와 runtime lifecycle 양쪽 경계를 소비하며, object store 호출 capability는 D9가 정의한 outbound 경계를 따른다.
테스트 계약
- oversized upload가 generic 500으로 처리되면 실패.
- temp cleanup contract: 다음 3 trigger가 모두 구현되어야 함: (a) success/failure on close (try-with-resources), (b) startup sweeper for orphaned files > 1h, (c) JVM shutdown hook backup. 측정 방법: contract test
TempFileCleanupContractTest에서File.createTempFile후 정상/예외/timeout 3 경로 각각의 cleanup 확인. orphan(>1h not closed) file이 startup sweeper에 의해 삭제되는지 verify. - path traversal input이 storage path로 전달되면 실패.
- download stream failure가 traceId 없이 로그되면 실패.
- antivirus 위치 명시 강제:
APP_FILE_UPLOAD_ENABLED=true이면 결정 사항에 antivirus 위치(gateway또는worker또는off중 1개)가 명시되어 있어야 함. 측정 방법: branch note의 결정 사항 라인에서antivirus.positiontoken grep. 미명시 시 readiness fail. default는gateway권고.
근거 (필수, 최소 1개+)
본 branch의 결정 근거. 상세 비교는 §외부 근거 / 대안 조사 (있다면) 참조.
| Source | 정당화하는 결정 |
|---|---|
| raw/company-tech-blogs/file-clamav-icap-gateway-scan | ClamAV + RFC 3507 ICAP (ca-tmpl antivirus gateway default의 표준 근거 |
| raw/official-docs/file-s3-presigned-url-upload | app/gateway 부담 0 vs antivirus 위치 분리 필요 + quarantine bucket |
| raw/official-docs/file-tus-resumable-upload-protocol | 100MB+ 영상에 적합 vs ca-tmpl "1h orphan cleanup"이 session 잘못 삭제 가능 |
| raw/official-docs/spring-boot-multipart-reference | D3 (upload size 메커니즘) + D4 (Spring multipart enforcement SSOT 메커니즘) — official-vendor-doc |
| raw/official-docs/nginx-client-max-body-size | D4 (gateway/WAF 보조 layer 메커니즘 — client_max_body_size directive) — official-vendor-doc |
| raw/official-docs/owasp-file-upload-cheat-sheet | D5 (3-layer defense-in-depth: extension/Content-Type/저장 위치 다층 검증) + D7 (webroot 밖 저장) — official-reference |
| raw/official-docs/jdk-files-createtempfile | D6 (temp file cleanup 메커니즘: DELETE_ON_CLOSE + shutdown-hook + deleteOnExit) — official-vendor-doc |
| raw/official-docs/iana-media-types-registry | D7 (content-type allowlist 6종이 IANA top-level types 내) — official-standard |
| raw/official-docs/spring-streaming-response-body | D8 (streaming download 메커니즘: StreamingResponseBody + ResponseEntity) — official-vendor-doc |
| raw/official-docs/owasp-path-traversal | Path-traversal claim (공격 정의 + 벡터 + "known good only" allowlist 방어 원칙) — official-reference |
외부 근거 / 대안 조사 (2026-05-22 — Group G-J: File / Resource Handling)
본 branch의 Spring 10MB + global 12MB + gateway 20MB 3-layer + content-type allowlist 6종 + temp orphan 1h cleanup + antivirus gateway default + path traversal opaque key 결정에 대한 외부 source.
- 채택 결정 (app via 3-layer + gateway antivirus + ClamAV/ICAP):
- raw/company-tech-blogs/file-clamav-icap-gateway-scan — ClamAV + RFC 3507 ICAP (ca-tmpl antivirus gateway default의 표준 근거)
- 검토한 대안:
- 대안 1: Direct S3 presigned URL upload (app via 우회) — raw/official-docs/file-s3-presigned-url-upload (app/gateway 부담 0 vs antivirus 위치 분리 필요 + quarantine bucket)
- 대안 2: tus resumable upload protocol — raw/official-docs/file-tus-resumable-upload-protocol (100MB+ 영상에 적합 vs ca-tmpl "1h orphan cleanup"이 session 잘못 삭제 가능)
- 대안 3: in-app ClamAV daemon scan —
file-clamav-icap-gateway-scan동일 source 안에서 in-app/gateway/async 3종 비교 (in-app은 app instance에 daemon dependency) - 대안 4: Post-upload async scan (S3 + Lambda ClamAV) — 동일 source (app/gateway 부담 0 vs scan 완료 전 객체 존재 → quarantine bucket 분리 필요)
- 비교 핵심: ca-tmpl "gateway default" 선택은 app instance scaling과 무관한 일정 throughput + in-app daemon dependency 회피. HTTPS E2E TLS 환경에서는 ICAP 적용 어려움 — 그 경우 post-upload async가 대안. tus 채택 시 ca-tmpl "1h orphan cleanup"은 session 정상 case도 삭제할 위험 — session ↔ orphan threshold 분리 보강 필요.
마주친 문제
- 아직 없음.
관련 일일 노트
- 없음.
완료 후 정리
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경:
- wiki 추출 대상 (verified만,
wiki/projects/로만 추출):actually-implemented항목:locally-verified항목:prod-verified항목:
- 추출하지 않을 항목 (planned / documented-only / abandoned):