Files
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

83 lines
3.0 KiB
Markdown

# 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.
```yaml
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:
```yaml
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
```bash
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
```