Skip to content

FileStore 개발자 인수인계 문서 ​

작성일: 2026-09-05

대상 저장소: hohyun94/FileStore

현재 브랜치: main

현재 마지막 커밋: 2ab4887 Log safe R2 object operation failures

배포 서비스: 관리형 클라우드 H Project / production / FileStore

서비스 ID: 19d16fe6-0797-4b90-868b-5f75d610a946

1. 현재 결론 ​

FileStore의 Stage 1 구현은 대부분 완료되었습니다. backend 설정, 포탈별 policy, PostgreSQL 저장, 관리자 인증, 업로드 세션, presigned upload URL 생성은 동작합니다. 실제 R2 통합 테스트에서 upload-session과 signed PUT까지 성공했습니다.

현재 남은 장애는 signed PUT 이후 FileStore 서버가 R2에 보내는 HeadObject 요청과 실패 시 정리 목적으로 보내는 DeleteObject 요청입니다. 테스트는 complete 단계에서 중단됩니다.

현재 테스트는 R2에 객체를 업로드하는 단계까지 성공했지만, FileStore 서버가 객체의 크기를 확인하지 못해 ACTIVE 상태로 전환하지 못하고 있습니다.

관리형 클라우드 dashboard의 CLI 인증과 로그 조회는 마지막 작업 시점에 완료되지 않았습니다. 다음 개발자는 Windows 관리형 클라우드 CLI 또는 관리형 클라우드 Dashboard의 FileStore Deployments 상세 로그에서 구체적인 AWS 오류명과 HTTP status를 먼저 확인해야 합니다.

2. 시스템 상태 ​

항목상태확인 내용
FileStore health정상/healthz가 HTTP 200 반환
PostgreSQL persistence정상health 응답에 persistence: postgresql 표시
PostgreSQL backend/policy 조회정상storageBackends: 1, consumerPolicies: 1
process-center policy정상활성화, read/write 활성화
PortalConsole 조직 IDAPI 검증 통과현재 API route가 dept_... 문자열을 허용
upload-session성공실제 파일 UUID 발급
presigned PUT성공Cloudflare R2에 signed upload 완료
complete / HeadObject통과HTTPS endpoint 정규화 후 객체 크기 확인 성공
read-url download통과실제 다운로드 바이트가 테스트 원문과 일치
DeleteObject cleanup통과관리자 cleanup 실행으로 R2 객체 2개 삭제, objectDeletedAt 및 CLEANUP_DELETED 감사 로그 확인
legal hold cleanup 보류통과legalHold=true 파일에서 skipped=1, deleted=0, objectDeletedAt=null 및 LEGAL_HOLD_UPDATED 감사 로그 확인
관리형 클라우드 global logs확인 실패최근 15분에 로그가 표시되지 않음
관리형 클라우드 CLI설치만 완료인증은 미완료

현재 health 응답의 기준 형태는 다음과 같습니다.

json
{
  "service": "file-store",
  "status": "ok",
  "persistence": "postgresql",
  "storageBackends": 1,
  "consumerPolicies": 1,
  "configurationPath": "filestore-config.json"
}

3. PostgreSQL 전환 내용 ​

FileStore는 DATABASE_URL이 설정되면 자체 PostgreSQL repository를 사용합니다. PortalConsole 또는 ProcessCenter의 기존 application table은 수정하지 않습니다.

FileStore가 사용하는 테이블은 다음과 같습니다.

테이블용도
file_store_backendsR2/S3/local backend 메타데이터
file_store_policies소비 포탈별 저장 정책
file_store_assets첨부파일 메타데이터와 lifecycle 상태
file_store_audits감사 로그
file_store_admin_accounts관리자 계정, 역할, scrypt 비밀번호 해시, 활성화 상태

PostgreSQL 환경변수는 다음과 같습니다.

env
DATABASE_URL=postgresql://...
DATABASE_DIALECT=postgresql
DB_POOL_MAX=5
DATABASE_SSL=require

DATABASE_URL이 없으면 로컬 JSON repository와 파일 기반 관리자 인증을 사용합니다. DATABASE_URL이 있으면 관리자 인증도 PostgreSQL 기반으로 전환되며 FILE_STORE_ADMIN_AUTH_PATH는 읽지 않습니다.

PostgreSQL 관리자 계정 테이블이 비어 있는 최초 기동 시 다음 환경변수로 OWNER 계정을 생성합니다.

env
FILE_STORE_ADMIN_USERNAME=admin
FILE_STORE_ADMIN_PASSWORD=<12자 이상>

초기 계정 생성 후 비밀번호 환경변수는 삭제하거나 교체하는 것이 안전합니다. 기존 admin-auth.json을 DB로 자동 import하는 기능은 구현하지 않았습니다.

관련 구현 파일은 다음과 같습니다.

text
src/postgres.ts
src/postgresRepositories.ts
src/adminAuth.ts
docs/SHARED_POSTGRES_DATABASE.md

4. 현재 backend와 policy ​

배포된 process-center policy 조회 결과는 다음과 같습니다.

json
{
  "id": "c44b65bd-bdc4-4cdc-b6eb-cb9dfcb61707",
  "consumerId": "process-center",
  "backendId": "rs-primary",
  "enabled": true,
  "writeEnabled": true,
  "readEnabled": true,
  "allowedContentTypes": [
    "application/pdf",
    "image/png",
    "image/jpeg"
  ]
}

R2 테스트에서 사용하는 policy UUID는 다음입니다.

text
c44b65bd-bdc4-4cdc-b6eb-cb9dfcb61707

조직 ID는 PortalConsole에서 전달된 식별자이며 UUID가 아닙니다.

text
dept_58016148e5504c1c98deb7182d02e224

따라서 organizationIds는 UUID 전용으로 검증하면 안 됩니다. 현재 다음 두 HTTP route가 문자열 식별자를 허용하도록 수정되어 있습니다.

text
POST /api/file-store/v1/assets/upload-session
POST /api/file-store/v1/assets

현재 validation 형태는 다음과 같습니다.

ts
organizationIds: z.array(z.string().trim().min(1).max(160))

5. R2 테스트 실행 방법 ​

로컬의 FileStore/.env.r2.integration.local에는 서버 URL과 서비스 토큰이 있으며, R2 secret은 저장하지 않습니다. 테스트 실행 시 환경변수 파일을 불러오고 policy 및 조직 ID를 지정합니다.

bash
cd /home/ubuntu/FileStore
set -a
. .env.r2.integration.local
set +a

export FILE_STORE_TEST_MAPPING_ID='c44b65bd-bdc4-4cdc-b6eb-cb9dfcb61707'
export FILE_STORE_TEST_ORGANIZATION_ID='dept_58016148e5504c1c98deb7182d02e224'
export FILE_STORE_TEST_CONTENT_TYPE='application/pdf'

node scripts/verify-r2-flow.mjs

Windows PowerShell에서는 다음처럼 실행합니다.

powershell
$env:FILE_STORE_TEST_MAPPING_ID = "c44b65bd-bdc4-4cdc-b6eb-cb9dfcb61707"
$env:FILE_STORE_TEST_ORGANIZATION_ID = "dept_58016148e5504c1c98deb7182d02e224"
$env:FILE_STORE_TEST_CONTENT_TYPE = "application/pdf"
node scripts/verify-r2-flow.mjs

테스트의 의도된 흐름은 다음과 같습니다.

text
upload-session
→ presigned PUT
→ complete and HeadObject verification
→ read-url issuance
→ downloaded content checksum comparison
→ DELETE / soft delete
→ deleted asset read-url rejection

6. 최근 테스트 결과 ​

최근 성공 로그:

text
PASS upload-session assetId=bc1ca949-2a37-4e57-a61f-465bca6ebf00
PASS signed upload

그 다음 단계의 실패:

text
POST /api/file-store/v1/assets/{assetId}/complete failed: HTTP 400
업로드된 객체의 크기를 확인할 수 없습니다.

정리 요청의 실패:

text
DELETE /api/file-store/v1/assets/{assetId} failed: HTTP 400
@aws-sdk XML parse error: mismatched tags <hr> and </body>.
Deserialization error

실패한 테스트에서 생성된 파일은 complete 이전 상태로 DB에 남아 있을 수 있습니다. 실패한 파일 ID 예시는 다음과 같습니다.

text
ac866231-ed3f-43cb-adfc-0c5a192a6894
bc1ca949-2a37-4e57-a61f-465bca6ebf00
b29e5fdd-a75a-4eba-a27f-22365a4951d0
0eb6e263-0303-4626-8ecb-9502c5292ef8

이 파일들은 운영 데이터가 아닌 통합 테스트 잔여 데이터로 분류하고, R2 객체와 PostgreSQL metadata를 확인한 뒤 정리해야 합니다.

7. 진단 코드 ​

src/storage.ts에 R2 object operation 실패 시 credential 또는 signed URL을 출력하지 않는 안전한 로그를 추가했습니다.

로그 형식은 다음과 같습니다.

text
[file-store] object HEAD failed {
  operation: "HeadObject",
  bucket: "...",
  error: "...",
  status: 403
}

[file-store] object DELETE failed {
  operation: "DeleteObject",
  bucket: "...",
  error: "...",
  status: 403
}

진단 로그를 추가한 마지막 커밋은 다음입니다.

text
2ab4887 Log safe R2 object operation failures

다음 개발자는 해당 커밋이 실제 관리형 클라우드 FileStore deployment에 배포되었는지 먼저 확인해야 합니다. 공개 health 응답에 persistence: postgresql이 있더라도 진단 로그 코드는 별도 최신 배포 여부를 확인해야 합니다.

8. 우선 확인할 원인 ​

signed PUT이 성공하고 서버-side HEAD 및 DELETE가 실패하므로 다음 항목을 우선 확인합니다.

확인 항목기준
Cloudflare API Token 권한Object Read & Write
Token bucket scope실제 테스트 bucket 포함
R2 endpointhttps://<ACCOUNT_ID>.r2.cloudflarestorage.com
endpoint pathbucket 이름을 URL path에 붙이지 않음
backend providerCLOUDFLARE_R2
backend regionauto
backend bucket실제 R2 bucket 이름과 일치
secretRef예: R2_PRIMARY
관리형 클라우드 variable 1<secretRef>_ACCESS_KEY_ID
관리형 클라우드 variable 2<secretRef>_SECRET_ACCESS_KEY

예를 들어 backend의 secretRef가 R2_PRIMARY이면 관리형 클라우드 환경변수는 정확히 다음 이름이어야 합니다.

env
R2_PRIMARY_ACCESS_KEY_ID=...
R2_PRIMARY_SECRET_ACCESS_KEY=...

Cloudflare R2 endpoint는 다음 형식이어야 합니다.

text
https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com

잘못된 형식은 다음과 같습니다.

text
https://<ACCOUNT_ID>.r2.cloudflarestorage.com/<BUCKET_NAME>

9. Windows 관리형 클라우드 CLI 로그 조회 절차 ​

다음 개발자가 Windows에서 로그를 조회하려면 PowerShell에서 실행합니다.

powershell

FileStore 프로젝트 디렉터리에서 프로젝트와 서비스를 연결합니다.

powershell
cd C:\path\to\FileStore

선택값은 다음과 같습니다.

text
Project: H Project
Environment: production
Service: FileStore

서비스 상태와 로그는 다음 명령으로 확인합니다.

powershell

서비스 ID를 직접 지정할 수도 있습니다.

powershell

PowerShell에서 R2 진단 로그만 찾으려면 다음을 사용합니다.

powershell
  Select-String -Pattern "HEAD failed|DELETE failed|HeadObject|DeleteObject|error|status"

bucket, error, status만 인수인계 문서에 기록하고 Access Key, Secret Access Key, signed URL은 기록하지 않습니다.

10. 커밋 이력 ​

주요 작업 커밋은 다음과 같습니다.

커밋내용
e680582관리자 UI에서 policy UUID 표시
4656168PortalConsole 조직 식별자 지원
1586f54R2 verifier MIME type 선택 지원
7250e62backend/policy/asset/audit PostgreSQL 저장
9b3c3cd관리자 인증 정보 PostgreSQL 저장
ca326e1health 응답에 persistence mode 표시
1043a7c실제 upload route의 조직 ID UUID 검증 수정
686b908Node fetch signed PUT body를 Blob으로 수정
2ab4887R2 HEAD/DELETE 안전 진단 로그 추가

원격 저장소와 로컬 main은 마지막 확인 시 일치했습니다.

text
main...origin/main

11. 다음 개발자의 작업 순서 ​

첫째, Windows 관리형 클라우드 CLI로 인증한 뒤 FileStore 서비스와 production 환경을 연결합니다.

둘째, 최신 deployment commit이 2ab4887 이상인지 확인합니다. 최신 배포가 아니면 main의 최신 커밋으로 재배포합니다.

셋째, 배포 로그에서 HeadObject 및 DeleteObject 진단 행을 확인합니다. 실제 status와 error 값을 기록합니다.

넷째, status가 403이면 R2 API Token의 Object Read & Write 권한과 bucket scope를 수정합니다. status가 404이면 endpoint, bucket 이름, path-style 요청 문제를 확인합니다. status가 301 또는 3xx이면 endpoint 또는 jurisdiction endpoint를 확인합니다. AWS XML parse error가 계속되면 응답 HTML의 원인이 되는 endpoint 또는 Cloudflare gateway 응답을 확인합니다.

다섯째, R2 설정을 수정한 뒤 다음 명령으로 테스트를 재실행합니다.

powershell
$env:FILE_STORE_TEST_MAPPING_ID = "c44b65bd-bdc4-4cdc-b6eb-cb9dfcb61707"
$env:FILE_STORE_TEST_ORGANIZATION_ID = "dept_58016148e5504c1c98deb7182d02e224"
$env:FILE_STORE_TEST_CONTENT_TYPE = "application/pdf"
node scripts/verify-r2-flow.mjs

여섯째, 최종적으로 다음 출력이 모두 나오는지 확인합니다.

text
PASS upload-session
PASS signed upload
PASS complete
PASS read-url download content matches
PASS soft delete
PASS deleted asset read-url
R2 integration flow passed

12. 보안 주의사항 ​

R2 Secret Access Key와 관리형 클라우드 service token은 채팅, Git, 문서, 로그에 기록하지 않습니다. 지금까지 테스트 과정에서 노출된 것으로 의심되는 service token 또는 R2 credential은 검증 완료 후 교체해야 합니다.

테스트 파일과 실패한 pending 파일을 정리한 뒤에도 R2 bucket과 PostgreSQL audit log에 잔여 데이터가 남아 있는지 확인해야 합니다.

References ​

13. 2026-09-06 운영 검증 업데이트 ​

관리형 클라우드 H Project / production / FileStore 서비스에 main의 cleanup job 커밋 898cbee가 자동 배포되었고, 관리형 클라우드 화면에서 Deployment successful 및 ACTIVE 상태를 확인했다. FileStore production 환경에는 FILE_STORE_CLEANUP_INTERVAL_MS=3600000이 추가되어 1시간 주기로 DELETED 객체 cleanup이 실행된다.

배포 후 공개 endpoint 검증 결과는 다음과 같다.

Endpoint결과
/healthzHTTP 200, PostgreSQL persistence, backend 1개, policy 1개
/adminHTTP 200, FileStore 관리자 HTML 정상 반환

배포 서비스는 Southeast Asia, 1 Replica, Online 상태이며 최신 배포 설명은 feat: add deleted asset cleanup job이다.