Files

Authenticated file storage

Use one file API with generated storage keys whether objects live beneath the local data directory or in a private S3-compatible bucket.

Upload

curl -X POST "$TRESTLE_URL/api/v1/files" \
  -H "Authorization: Bearer $TRESTLE_TOKEN" \
  -F "file=@avatar.png" \
  -F "collection=profiles" \
  -F "recordId=rec_123"

The client filename is metadata, never a path. Trestle stages local writes, hashes content, commits metadata and atomically publishes the generated key.

Download a range

curl "$TRESTLE_URL/api/v1/files/file_123" \
  -H "Authorization: Bearer $TRESTLE_TOKEN" \
  -H "Range: bytes=0-1048575" \
  --output first-megabyte.bin

Delete and reconcile

Deletion is durable and fail-closed. A delete records durable deletion intent and makes the file unavailable to readers in one transaction, then removes the provider object, then finalizes. A failed step returns an error and changes nothing; an object is never removed before durable intent exists. If the provider delete fails, the file stays unavailable, the deletion stays pending, and Trestle resumes it at startup and on a bounded periodic recovery worker during normal operation (the resume path is idempotent). Recovery target selection fails closed: an object is only removed once its metadata is absent or marked deleted, and a live metadata reference to a storage key blocks deletion, logs a conflict and leaves it pending. Administrators can run orphan reconciliation from the Files dashboard for objects without metadata. Quotas are checked before accepting a write and exclude files whose deletion has begun.

Choose a provider

  • Local: simplest single-node deployment; include the file tree in backups.
  • S3-compatible: private object storage with SigV4; back up objects according to provider policy because Trestle archives contain their manifest, not remote bytes.

Dogfood path

The incident tracker binds a Markdown runbook to an incident and proves a narrowly scoped service identity can retrieve the exact bytes. See the file workflow.

Provider storage

File metadata, quotas and record bindings live in the database and behave identically on both providers; the file bytes are stored by the local or S3-compatible backend independently of the database provider. Orphan reconciliation and quota enforcement run the same provider-parameterized suite.