Files
clean-architecture-backend-…/docs/fileserver/upgrade-guide.md
T
DongHyeonkaandClaude Opus 5 5f10b791d3 chore: record pre-existing uncommitted repository state
Snapshot of the in-flight state that already existed, identically, in both
this worktree and the main checkout before this session began: the initial
HTTP Client platform implementation (previously untracked), the redis-lab
removal, and the JPA / object-storage / notification integration work.

Kept separate from this session's HTTP Client review response, which lands
in the following commit, so the two bodies of work stay reviewable apart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 16:48:43 +09:00

3.0 KiB

Fileserver upgrade guide

Enabling the capability

The Fileserver ships off. Nothing is registered — no endpoint, no thread pool, no metric — until it is enabled explicitly.

ca-skeleton:
  fileserver:
    enabled: true
    instance-id: ${HOSTNAME}
    default-namespace: default
    observability:
      fingerprint-key: ${FILESERVER_FINGERPRINT_KEY}

instance-id must be unique per instance: it is the writer-lease owner, and two nodes sharing one would both believe they hold the same lease.

fingerprint-key is required and has no default. Startup fails without it rather than falling back to an unkeyed digest, which would be reversible for an enumerable identifier space.

Optional surfaces

Each is a separate switch, and each defaults to off:

ca-skeleton:
  fileserver:
    admin:
      enabled: false        # management plane; intended for a management port
    tus:
      enabled: false        # tus 1.0 Stable
    httpbis-draft12:
      enabled: false        # Experimental; unratified, may change without notice
    nginx:
      enabled: false        # front-proxy delegation; needs a validated internal location

Database schema

The metadata schema is installed as a capability migration and starts inactive:

V1__create_fileserver_metadata.sql  →  capability_schema_registry: jpa-fileserver-metadata-v1

Activate it deliberately. Enabling the capability without an activated schema fails at startup rather than at the first upload.

Choosing a publish mode

Mode When
atomic-move-preferred Default. Uses an atomic rename when the probe proves one, else a metadata pointer.
atomic-move-required Fail closed. Refuses to start on storage that cannot prove an atomic move.
metadata-pointer For storage without atomic rename; publication is the metadata commit.

Pick atomic-move-required when the storage is certified and you want a misconfiguration to surface at boot rather than at publish time.

Behaviour that will surprise you

  • A delete answers 202, not 204, when content still exists. The file is already unreadable; the physical reclaim is deferred. Treating 202 as a failure will produce spurious retries.
  • A batch upload answers 200 even when parts failed. The batch is explicitly non-atomic, and a single status could not report a partial outcome honestly. Read results[].problem.
  • An ambiguous failure must not be retried. Check "ambiguous": true in the problem document.
  • If-Match takes the strong ETag, not a version number. A client can only assert about the representation it was actually served.
  • Inline rendering is refused for scriptable types even when the caller asks for it.

Verifying an upgrade

cd src
./gradlew verifyCleanArchitectureDependencies --console=plain
./gradlew :application-core:check :adapter:inbound:web:check \
          :adapter:outbound:fileserver:check --console=plain
./gradlew :app-bootstrap:test --tests '*Fileserver*' --console=plain