Skip to main content

Storage

EUDIPLO requires persistent file storage for:

  • Credential offer artifacts (QR codes, deep links)
  • Uploaded trust list and certificate files
  • Temporary session-related assets

Storage is abstracted through a pluggable provider interface, allowing deployments to use local filesystem storage during development and S3-compatible object storage in production.

Configuration

Auto-generated. Do not edit manually. Run pnpm --filter @eudiplo/docs run prebuild (scripts/generate-config-docs.ts).

KeyTypeNotes
STORAGE_DRIVERstringThe storage driver to use (default: local)
LOCAL_STORAGE_DIRstringThe directory to store files in when using local storage [when STORAGE_DRIVER is {"override":true} | "local" → then default=undefined]
S3_REGIONstringThe AWS region for the S3 bucket [when STORAGE_DRIVER is {"override":true} | "s3" → then required]
S3_BUCKETstringThe name of the S3 bucket [when STORAGE_DRIVER is {"override":true} | "s3" → then required]
S3_ACCESS_KEY_IDstringThe access key ID for the S3 bucket [when STORAGE_DRIVER is {"override":true} | "s3" → then required]
S3_SECRET_ACCESS_KEYstringThe secret access key for the S3 bucket [when STORAGE_DRIVER is {"override":true} | "s3" → then required]
S3_ENDPOINTstringThe endpoint URL for the S3 service (for S3-compatible services) [when STORAGE_DRIVER is {"override":true} | "s3"]
S3_FORCE_PATH_STYLEbooleanWhether to force path-style URLs for S3 [when STORAGE_DRIVER is {"override":true} | "s3" → then default=false]

Local Storage

Uses the server's local filesystem. Files are stored under the configured root directory:

STORAGE_ROOT/
tenants/
<tenant-id>/
offers/
<offer-id>.png
trust-lists/
<trust-list-id>.xml
certificates/
<cert-id>.pem

Environment Variables:

STORAGE_PROVIDER=local
STORAGE_ROOT=/app/storage

Use when: Development, single-node deployments, or when network storage is unavailable.

Limitations:

  • Not suitable for multi-instance deployments (no shared state)
  • Manual backup required
  • Limited scalability

S3 Storage

Uses S3-compatible object storage (AWS S3, MinIO, Azure Blob Storage via S3 API, Google Cloud Storage with S3 interop).

Environment Variables:

STORAGE_PROVIDER=s3
S3_ENDPOINT=https://s3.eu-central-1.amazonaws.com
S3_BUCKET=eudiplo-storage
S3_REGION=eu-central-1
S3_ACCESS_KEY_ID=<your-access-key>
S3_SECRET_ACCESS_KEY=<your-secret-key>
S3_FORCE_PATH_STYLE=false # Set to true for MinIO

Use when: Production deployments, multi-instance horizontally scaled setups, managed cloud infrastructure.

Benefits:

  • Shared storage across all EUDIPLO instances
  • Built-in durability and replication
  • Managed backup and lifecycle policies
  • No single point of failure

Extensibility

To add a new storage provider (e.g., Azure Blob Storage native API, Google Cloud Storage), implement the StorageProvider interface:

export interface StorageProvider {
putObject(key: string, body: Buffer | Readable, contentType: string): Promise<void>;
getObject(key: string): Promise<Buffer>;
deleteObject(key: string): Promise<void>;
objectExists(key: string): Promise<boolean>;
}

Then register it in StorageModule:

providers: [
{
provide: 'STORAGE_PROVIDER',
useFactory: (config: ConfigService) => {
const provider = config.get('STORAGE_PROVIDER');
if (provider === 'azure-blob') {
return new AzureBlobStorageProvider(config);
}
// ... existing providers
},
},
],

Accessibility

All stored objects are tenant-scoped via key prefixes:

  • tenants/{tenantId}/offers/{offerId}.png
  • tenants/{tenantId}/trust-lists/{trustListId}.xml

The storage provider ensures:

  • Tenant isolation (one tenant cannot access another's files)
  • Consistent key structure across providers
  • Automatic content-type detection

Multi-Tenant Storage

Each tenant's files are isolated by key prefix. Access control is enforced at the application layer before calling the storage provider:

// Application layer validates tenantId before storage operation
const key = `tenants/${tenantId}/offers/${offerId}.png`;
await storageProvider.putObject(key, buffer, 'image/png');

Example: Storing a credential offer QR code

const qrCodeBuffer = await QRCode.toBuffer(offerUrl);
const key = `tenants/${session.tenantId}/offers/${session.id}.png`;
await this.storageProvider.putObject(key, qrCodeBuffer, 'image/png');