Aller au contenu

v2.0.0

Ce contenu n’est pas encore disponible dans votre langue.

Overview

This release introduces file instruments: instruments whose responses are uploaded files (for example single documents or multi-file MRI scan sessions) rather than form data. To support this, Open Data Capture can now use an S3-compatible object storage service. Files are not stored in MongoDB; the browser uploads and downloads them directly via short-lived presigned URLs, and only file metadata is kept in the database.

The default Docker Compose stack now ships a self-hosted RustFS service for this purpose.

This is a non-breaking upgrade. Object storage is opt-in via the new STORAGE_ENABLED flag, which defaults to false. Existing deployments upgrade and boot unchanged; everything except file instruments works exactly as before. File instruments only become available once you enable storage (see below). When STORAGE_ENABLED=false, attempting to create a file-instrument record returns a clear 503 Service Unavailable rather than failing at startup.

What’s new

  • File instruments — a new FILE instrument kind with one or more file groups, each constrained by an allowed file type and a count (min/max).
  • Object storage service — a new rustfs service in the Compose stack, backed by a ./rustfs/data volume.
  • Direct browser uploads/downloads — files transfer directly between the browser and the storage service using presigned URLs, keeping large transfers off the API.
  • Two demo file instruments (ARBITRARY_SINGLE_FILE, MRI_SCAN_SESSION) are now seeded by the demo data.

New environment variables

The following variables have been added (see .env.template). “Required” means required only when STORAGE_ENABLED=true; when storage is disabled these are ignored.

VariableRequiredDescription
STORAGE_ENABLEDNoMaster switch for object storage / file instruments (default false). When true, the four variables marked “Yes” must all be set or the API refuses to start.
STORAGE_ENDPOINTYesInternal endpoint the API uses for S3 API calls. In Compose this is http://rustfs:9000.
STORAGE_PUBLIC_ENDPOINTNoExternally reachable endpoint embedded in presigned URLs. Defaults to http://localhost:${APP_PORT}/storage, which Caddy proxies to rustfs. Set this to your public storage URL (e.g. https://your-domain.com/storage) for real deployments.
STORAGE_ACCESS_KEYYesS3 access key. Also used as the RustFS admin access key in the Compose stack.
STORAGE_SECRET_KEYYesS3 secret key. Also used as the RustFS admin secret key in the Compose stack.
STORAGE_BUCKETYesBucket name where files are stored (default open-data-capture). Created automatically on startup if absent.
STORAGE_REGIONNoRegion name. Can be any value for self-hosted S3 (default us-east-1).
RUSTFS_VERSIONNoRustFS image tag for the Compose stack (default latest).

Upgrading without enabling storage

If you don’t need file instruments yet, no action is required — pull the new images and restart. STORAGE_ENABLED defaults to false, the bundled rustfs container boots with placeholder credentials but is otherwise unused, and the rest of the application is unchanged.

To enable file instruments later, follow the steps below.

Enabling object storage

1. Add the storage configuration

Set STORAGE_ENABLED=true and provide the storage credentials. If you generate your .env with scripts/generate-env.sh, re-run it — it now generates STORAGE_ACCESS_KEY and STORAGE_SECRET_KEY for you. Back up your existing .env first, since regenerating will also produce new values for other secrets.

Otherwise, copy the new STORAGE_* entries from .env.template into your existing .env and fill them in. At minimum:

Terminal window
STORAGE_ENABLED=true
STORAGE_ENDPOINT=http://rustfs:9000
STORAGE_PUBLIC_ENDPOINT=
STORAGE_ACCESS_KEY=$(openssl rand -hex 16)
STORAGE_SECRET_KEY=$(openssl rand -hex 32)
STORAGE_BUCKET=open-data-capture
STORAGE_REGION=us-east-1

When STORAGE_ENABLED=true, all of STORAGE_ACCESS_KEY, STORAGE_SECRET_KEY, STORAGE_BUCKET and STORAGE_ENDPOINT must be set or the API will refuse to start. Leave STORAGE_PUBLIC_ENDPOINT blank to use the Caddy-proxied default (http://localhost:${APP_PORT}/storage). Set it explicitly to your externally accessible storage URL for a production deployment behind a custom domain.

2. Update your reverse proxy

The bundled Caddyfile now proxies /storage/* to the storage service so the browser can reach presigned URLs:

handle_path /storage/* {
reverse_proxy rustfs:9000 {
header_up Host rustfs:9000
}
}

If you use the bundled Caddy configuration, pull the updated Caddyfile. If you run your own reverse proxy, add an equivalent route forwarding /storage/* to the storage service on port 9000, and ensure the upstream Host header matches the storage host. Otherwise, set STORAGE_PUBLIC_ENDPOINT to a URL your users’ browsers can reach directly.

3. Pull the updated Compose stack and restart

The updated docker-compose.yaml adds the rustfs service (with a ./rustfs/data bind mount) and wires the new variables into the api service. Make sure ./rustfs/data is on persistent, backed-up storage.

Terminal window
docker compose pull
docker compose up -d

On first boot the API creates the STORAGE_BUCKET automatically if it does not already exist.

Backups

File contents now live in object storage, not in MongoDB. Update your backup strategy to include the storage volume (./rustfs/data for the bundled stack, or your S3 bucket) alongside your existing database backups. A database backup alone will no longer capture uploaded files.

Notes

  • File uploads and downloads go directly from the browser to the storage service via presigned URLs, so the storage STORAGE_PUBLIC_ENDPOINT must be reachable from end users’ browsers, not just from the API container.
  • If you supply your own managed S3 (e.g. AWS S3, MinIO) instead of the bundled RustFS, point STORAGE_ENDPOINT/STORAGE_PUBLIC_ENDPOINT at it, set the matching credentials and region, and you can drop the rustfs service.