FileStore 아키텍처
명칭(2026-09-13): 제품·저장소 이름은 FileStore(이전
FileStore)다. DB(file_store,file_store_*테이블), 공개 경로/api/file-store/v1/*, 환경변수 접두FILE_STORE_*는 데이터·계약 호환을 위해 유지한다. 전체 규칙은UiPlatform/docs/PLATFORM_NAMING.md.
FileStore는 각 사용자 포탈의 첨부파일 원본을 저장·보호·감사하고, 승인된 파일을 RagService로 발행하는 독립 backend 서비스다. 사용자가 보는 첨부 기능의 UI·타입·클라이언트는 portal-foundation의 공통 패키지에 두며, FileStore는 브라우저에 스토리지 자격증명을 노출하지 않는다.
책임 분리
| 구성 요소 | 소유 책임 | 소유하지 않는 책임 |
|---|---|---|
portal-foundation Asset | 공통 첨부 UI, 업로드/목록/미리보기 API 타입, 포탈 임베드 컴포넌트 | 원본 저장, 버킷 credential, 출처 삭제 |
| FileStore | R2/S3/로컬 저장소, 포탈별 backend 매핑, 파일 lifecycle, 감사, RAG 발행 | 일반 사용자의 포탈 화면, 업무 엔터티 자체 |
| DirectoryService | 사용자·조직·포탈 등록, 중앙 bootstrap 관리자, 서비스 토큰/위임 검증 | 첨부 원본 저장, RAG 정제 |
| RAGCenter | FileStore가 승인·발행한 파일의 문서 인덱스·RAG·citation | 원본 파일 upload/download, 저장소 credential |
| ExploreGateway | 다중 포털 탐색 실행 조합(포털 어댑터 오케스트레이션) | 문서 인덱스, 원본 업무 데이터 |
| 사용자 포탈 | 업무 데이터/ACL, Asset UI 임베드, FileStore service API 호출 | 공통 저장 backend 운영 |
표기 정정(2026-09-13): 발행 대상은 RAGCenter(문서 정제·인덱싱·pgvector RLS 검색·citation 소유)다.
ExploreGateway는 포털 탐색 어댑터를 조합하는 오케스트레이터로, 문서 색인을 소유하지 않는다.ragPublishAllowed등 기존 API 필드명은 그대로 유지한다.
포탈별 저장소 매핑
관리자는 backend를 등록한 뒤 사용자 포탈에 하나 이상의 저장소 매핑을 부여한다. FileStore는 업로드 요청의 portalId와 mappingId가 일치하는지, 형식·용량·쓰기 정책이 허용되는지를 먼저 검증한다.
| 매핑 설정 | 목적 |
|---|---|
backendId | Cloudflare R2, 다른 S3 호환 스토리지, 또는 온프레미스 로컬 볼륨 선택 |
pathPrefix | backend 내부의 포탈 전용 key namespace |
allowedContentTypes, maxBytes | 포탈별 업로드 정책 |
encryptionRequired | 암호화 의무 |
readEnabled, writeEnabled | 포탈별 읽기·쓰기 차단 스위치 |
ragPublishAllowed | 파일이 scan/승인 뒤 RAGCenter로 발행될 수 있는지 여부 |
backend credential 원칙
S3/R2 backend 설정에는 secretRef만 저장한다. 예를 들어 secretRef: "R2_PRIMARY"는 server environment의 R2_PRIMARY_ACCESS_KEY_ID, R2_PRIMARY_SECRET_ACCESS_KEY를 참조한다. access key 원문은 관리 UI, 일반 database row, portal API 응답, RAG 발행 이벤트에 절대 포함하지 않는다.
온프레미스 로컬 backend는 localRoot를 Docker named volume 또는 호스트 마운트 지점으로 지정한다. FileStore는 객체 key를 canonicalize하고 .. 경로 이탈을 차단하며, local:// locator를 브라우저에 반환하지 않는다. 파일은 인증된 FileStore endpoint를 통해서만 스트리밍한다. 소비 포탈의 기본 경로는 포탈 서버가 원본을 중계(릴레이) 하는 것이고, 브라우저가 서명 URL을 직접 받는 구성은 FILE_STORE_ALLOWED_ORIGINS로 허용한 origin 에 한해 선택적으로 지원한다(src/corsHeaders.ts — 기본 꺼짐, 와일드카드·쿠키 자격증명 미사용).
lifecycle 및 RAG 발행
원본 파일은 PENDING_SCAN 상태에서는 RAG로 발행할 수 없다. ACTIVE 상태이면서 포탈 매핑의 ragPublishAllowed=true일 때만, 웹 URL이 아닌 filestore://assets/{assetId} locator와 무결성·권한 메타데이터를 RAGCenter에 전달한다.
DirectoryService 단계적 이관
기존 DirectoryService의 /api/directory/v1/media, asset relation, R2 inventory 기능은 즉시 제거하지 않는다. 전환 기간에는 기존 endpoint가 FileStore client를 호출하는 compatibility facade가 되어 기존 사용자 포탈을 보호한다. FileStore가 독립적으로 운영·검증된 뒤 DirectoryService schema와 endpoint를 제거한다.
Direct upload
운영 포털은 upload-session으로 presigned PUT URL을 받은 뒤 객체 저장소로 직접 업로드하고 complete를 호출합니다. backend와 consumer policy(max size, MIME, read/write, RAG 허용)는 FileStore 관리자 UI에서 관리합니다. DirectoryService에는 FILE_STORE_BASE_URL과 FILE_STORE_SERVICE_TOKEN만 설정하며, mapping ID는 consumer policy 조회로 자동 선택합니다.