Skip to main content
View as Markdown

Lifecycle & Quotas

A file uploaded through File Operations stays until something removes it. Two things can: an explicit DELETE, or the permanent removal of the record that referenced it. Everything else — including a soft-deleted record — leaves the bytes in place.

Files and Their Records

Attachments follow Sovrium's soft-delete-by-default posture, so file presence tracks record presence rather than the delete request:

What happens to the record What happens to the file
Soft-deleted (the default) Kept. A restore brings the attachment back intact.
Restored Nothing to do — the bytes never left.
Purged (?purge=true) Removed from storage, then the row is dropped.
Hard-deleted (?permanent=true) Kept. The row goes; the bytes are orphaned.
Attachment replaced on update The previous file is removed.
Attachment cleared to null The previous file is removed.
Key referenced by another record Kept, even during a purge.

Two rows deserve attention. The last one saves you: before deleting bytes during a purge, Sovrium checks whether any other record still points at the same key — soft-deleted records included — so two records sharing one upload cannot orphan each other.

The ?permanent=true row is the trap. It is the admin-only hard delete, and it drops the row without touching storage. Use ?purge=true when the file must go too; it needs only the ordinary delete permission and it cleans both sides.

Size Caps

Two operator-controlled limits bound uploads. Both are validated at boot: set either to a non-positive or non-numeric value and the server refuses to start rather than silently ignoring your cap.

Variable Default Bounds
STORAGE_MAX_FILE_SIZE 104857600 (100 MB) One upload. A bucket's own maxFileSize overrides it.
STORAGE_MAX_TOTAL_SIZE unlimited Every stored byte in the application, summed.
>_ terminal
STORAGE_MAX_FILE_SIZE=52428800      # 50 MB per file
STORAGE_MAX_TOTAL_SIZE=10737418240  # 10 GB in total

An oversized upload answers 413; one that would push the total past the quota answers 507. With no STORAGE_MAX_TOTAL_SIZE set there is no quota check at all, so uploads are bounded only per-file.

Reading Current Usage

>_ terminal
curl https://app.example.com/api/admin/buckets/overview \
  -H "Cookie: $ADMIN_SESSION"
app.json
{
  "totals": {
    "buckets": 1,
    "files": 1284,
    "totalBytes": 524288000,
    "by_provider": { "s3": 1, "local": 0, "bytea": 0 }
  },
  "series": {
    "interval": "1h",
    "points": [{ "timestamp": "2026-08-13T09:42:00.000Z", "uploads": 12, "bytes": 4194304 }]
  }
}

The endpoint is open to the admin and operator roles, and reports what is stored right now, not what is allowed — compare totals.totalBytes against your own STORAGE_MAX_TOTAL_SIZE to know how much headroom is left. Both totals.totalBytes and totals.files are read live from the storage backend rather than tracked in a counter, so deleting files lowers them immediately. totals.buckets counts the buckets your config declares; an app declaring none reports the single virtual default bucket, and one whose storage provider does not resolve reports zero.

Upload History

The series block answers when those bytes landed, which totals cannot. Each point reports the uploads count and bytes sum for one interval, read from the storage catalog — every upload path and every backend writes there, so the series summed across the window equals totals.

?period picks the window and defaults to 24h: 24h returns 24 hourly points, 7d seven daily ones, 30d thirty. Each point is labelled by the instant its interval opens, and the window is measured back from the moment you call rather than snapped to clock hours or midnight. period never affects totals. The catalog holds only files that still exist, so deleting one lowers the interval it was uploaded into.

Automation Temp Files

Automations that write scratch files put them under tmp/automations/. Those are reclaimed opportunistically — the next temp write sweeps anything older than the threshold. Nothing is scheduled, so the value is an age, not an interval.

Variable Default Meaning
STORAGE_TEMP_CLEANUP_AFTER 86400000 (24 h) Age in milliseconds at which a temp file becomes sweepable.

Set it to 0 to disable app-level sweeping entirely — the right choice when an S3 lifecycle rule already reclaims the prefix. Any other malformed value falls back to 24 hours rather than disabling the sweep, because silently unbounded growth is the worse failure.

Last updated September 1, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.

Built with Sovrium