feat: instance settings + instance-wide storage cap (backend)#98
Merged
Conversation
ravirajsinh45
added a commit
that referenced
this pull request
Jul 6, 2026
This was referenced Jul 6, 2026
ravirajsinh45
added a commit
that referenced
this pull request
Jul 7, 2026
MediaFile.file_size_bytes and CommentAttachment.file_size_bytes were INTEGER (int4, ~2.1GB ceiling), so files >2GB could not be recorded — undermining #64 (unlimited per-file uploads) and #98 (instance storage accounting). Migrate both columns to BigInteger with an alembic migration. Structural tests added.
…tion Adds an admin-editable instance_settings singleton table for a future instance-wide storage cap. storage_limit_bytes defaults to 0 (unlimited). Note: the brief specified revision id f1a2b3c4d5e6, but that id already exists in this repo's applied migration history (f1a2b3c4d5e6_add_poster_s3_key_to_projects.py), so a new unique revision id (dfcdaa30f89e) was generated instead. down_revision (8ca3dffea55f) and all schema/behavior are otherwise unchanged from the brief.
get_or_create_instance_settings and GET /instance/settings could each insert a row on concurrent first-time access, producing duplicate rows and letting the storage cap silently fail open. GET is now read-only (defaults to unlimited when no row exists) and creates use a fixed sentinel PK so concurrent inserts collide via IntegrityError instead of duplicating.
…x with 422 (review #98)
a4515fc to
44a1a45
Compare
ravirajsinh45
added a commit
that referenced
this pull request
Jul 7, 2026
MediaFile.file_size_bytes and CommentAttachment.file_size_bytes were INTEGER (int4, ~2.1GB ceiling), so files >2GB could not be recorded — undermining #64 (unlimited per-file uploads) and #98 (instance storage accounting). Migrate both columns to BigInteger with an alembic migration. Structural tests added.
ravirajsinh45
added a commit
that referenced
this pull request
Jul 7, 2026
MediaFile.file_size_bytes and CommentAttachment.file_size_bytes were INTEGER (int4, ~2.1GB ceiling), so files >2GB could not be recorded — undermining #64 (unlimited per-file uploads) and #98 (instance storage accounting). Migrate both columns to BigInteger with an alembic migration. Structural tests added.
ravirajsinh45
added a commit
that referenced
this pull request
Jul 7, 2026
* fix: widen file_size_bytes to BigInteger (int4 -> bigint) MediaFile.file_size_bytes and CommentAttachment.file_size_bytes were INTEGER (int4, ~2.1GB ceiling), so files >2GB could not be recorded — undermining #64 (unlimited per-file uploads) and #98 (instance storage accounting). Migrate both columns to BigInteger with an alembic migration. Structural tests added. * docs(changelog): add file_size_bytes bigint fix under [Unreleased] (#99) * docs(migration): warn that int4->int8 widen locks media_files (ACCESS EXCLUSIVE) (review #99)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an admin-editable
instance_settingssingleton table — the foundation forinstance-level settings on this single-tenant, self-hosted deployment — with an
instance-wide total-storage cap as its first setting, enforced at upload time.
Backend only; the admin UI and a real storage indicator are a separate follow-up.
Context: emerged from #64 (configurable per-file cap + removal of a fake per-project
"10 GB" indicator). FreeFrame is single-tenant — one implicit org == the instance —
so an "org-level" cap is really an instance-level cap.
What's added
InstanceSettingsmodel + migration — single-row table (fixed sentinel PK →true singleton),
storage_limit_bytesBigInteger (0= unlimited). Sibling tofeat: Instance branding — white-label logos, org name, favicon, Powered by FreeFrame #90's
instance_branding, kept separate by concern.services/storage.py—instance_storage_used_bytes(committed-only usage:processing/ready, non-deleted),
get_storage_limit,storage_cap_error, andupload_guard_error(per-fileMAX_UPLOAD_BYTESfirst, then the instance cap).GET /instance/settings(any member →{storage_limit_bytes, storage_used_bytes},read-only) and
PUT /instance/settings(admin). Per-role curated response;storage numbers never exposed to unauthenticated callers.
MediaFile row is created. Initiate-only (concurrent-burst race documented).
Per-file env cap unchanged.
Design decisions
0= unlimited everywhere (consistent withMAX_UPLOAD_BYTES).concurrent first access).
Testing
apps/api/tests/test_instance_settings.py(model, service, router auth/shape,enforcement, singleton no-row default).
instance_storage_used_bytesran against the dev DB → 13.2 MB; over-cap andunlimited branches verified.
Follow-ups (out of scope)
one removed in UI shows hardcoded "/ 10 GB" project storage cap; backend hard-rejects files > 10 GB #64).
MediaFile.file_size_bytesisInteger(int4, ~2.1 GB/row ceiling) →should become
BigInteger.routers/projects.pyper-project storage sum to committed-only semantics.8ca3dffea55f—whichever merges second needs an
alembic merge.