--- kind: CONCEPT slug: file-state-machine-and-ready title: 파일 상태 기계와 READY가 뜻하는 것 topic: fileserver-state-and-fencing project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 basisVersion: PostgreSQL 16 · Spring Boot 4.0.8 · 리비전 21234e38 rootTreeNode: concept:file-state-machine-and-ready evidenceCapturedOn: 2026-09-01 assets: - key: file-state-machine-and-ready file: ../../../final/evidence/rendered/file-state-machine-and-ready.svg - key: file-state-machine-and-ready-diagram file: ../../../final/assets/diagrams/file-state-machine-and-ready/file-state-machine-and-ready.svg evidence: - ../../../final/evidence/raw/file-state-machine-and-ready.txt source: - 원본 분석 절은 final/document.md#4-4 · final/document.md#a08 §V1 이다. --- # 파일 상태 기계와 READY가 뜻하는 것 파일이 공개적으로 읽을 수 있는지는 파일시스템이 아니라 관계형 레코드가 정한다. 그래서 모든 상태 전이가 상태와 버전 양쪽으로 가드된다. ## 관계 - **공개 읽기 가능한 상태는 완전한 identity를 DB 제약으로 요구한다** 이 개념에서 끌어낸 규칙이다. - **물리 경로와 원본 파일명을 저장하지 않는다** 이 메타데이터가 무엇을 담지 않는지 정한 결정이다. - **claim이 소유자와 토큰과 만료를 기록하지 않아 죽은 worker의 항목이 영영 남았다** 같은 리프의 상태 기계에서 나온 사례다. ## 본문 파일이 11개 상태를 지나고 **공개 읽기 가능한 상태는 `READY` 하나뿐**이라는 설계의 설명이다. V1 헤더가 원칙을 적는다 — "파일시스템이 아니라 관계형 레코드가 파일이 공개적으로 읽을 수 있는지 결정한다." ## 공개 읽기가 가능한 상태 :::evidence key="file-state-machine-and-ready-diagram" alt="READY 만 공개 읽기 가능 경계 안에 놓이고 업로드 중과 검증 중, 실패와 삭제 대기가 바깥에 빗금으로 놓인다" caption="공개 읽기가 가능한 상태" zoom="false" ::: ## 전이와 완전성을 무엇이 가드하나 모든 전이가 `state`와 `version` 둘 다로 가드되고, `READY`의 완전성이 DB CHECK 제약으로 강제된다 — `content_key`·`actual_size`·`sha256`·`strong_etag`·`published_at`이 전부 NOT NULL이다. ## V1 헤더가 적은 원칙 :::evidence key="file-state-machine-and-ready" alt="분석 문서 final/document.md 에서 이 기록의 근거 절을 그대로 잘라낸 18줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md 발췌 — 18줄" zoom="true" ::: ## 저장하지 않는 것 물리 경로·마운트·원본 물리 파일명을 저장하지 않는다 — `content_key`는 서버 생성 opaque key이고 `original_name`은 신뢰할 수 없는 표시용 텍스트다. :::note 컨테이너 레인 미실행 ::: ## 진실의 출처 ```sql -- Fileserver platform metadata. The relational record — not the filesystem — decides whether a -- file is publicly readable, so every state transition is guarded by both `state` and `version`. ``` 파일시스템에 바이트가 있다는 것이 공개 가능하다는 뜻이 아니다. 레코드가 그것을 정한다. 이 선택의 결과가 전이 가드다. 상태만 보면 동시에 두 전이가 일어날 수 있으므로 버전도 함께 본다. ## 무엇을 담지 않는가 ```sql -- No physical path, mount, or original physical filename is stored here: `content_key` is a -- server-generated opaque key and `original_name` is untrusted display text only. ``` 세 가지를 담지 않는다. 물리 경로와 마운트와 원본 물리 파일명이다. 콘텐츠 키는 서버가 만든 불투명 키다. 원본 이름은 신뢰할 수 없는 표시용 텍스트일 뿐이라고 명시된다. 즉 그 값으로 무언가를 찾거나 열지 않는다. ## 스키마가 자기 전제를 검사한다 ```sql DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM capability_schema_registry WHERE capability_id = 'jpa-flyway-migration' AND core_epoch >= 1 AND lifecycle_state = 'ACTIVE' ) THEN RAISE EXCEPTION 'fileserver metadata requires active core epoch 1'; END IF; ``` 이 스트림은 코어 에포크가 활성일 때만 적용된다. 능력 스키마 레지스트리가 그 사실을 답한다. :::note 스키마 설치와 사용 승인을 나눈 레지스트리가 여기서 실제로 쓰인다. 이 마이그레이션은 레지스트리에 질의해 전제를 확인하고, 아니면 예외로 멈춘다. ::: ## 상태와 버전이 함께 가드하는 이유 상태만으로 전이하면 같은 상태에서 출발한 두 전이가 모두 성공할 수 있다. 버전을 함께 조건에 넣으면 하나만 성공하고 다른 하나는 갱신 건수 0 이 된다. 이 형태는 이 저장소의 다른 상태 기계와 같다. 소유자 튜플을 조건에 반복하고 갱신 건수를 답으로 쓰는 구조다. ## 공개 가능 상태의 무게 공개적으로 읽을 수 있는 상태는 다른 상태보다 요구가 많다. 그 상태에 도달한 레코드는 신원이 완전해야 하고, 그 완전성은 애플리케이션 검사가 아니라 데이터베이스 제약으로 표현된다. 애플리케이션 검사로 두면 그 검사를 지나지 않는 경로가 언젠가 생긴다.