Skip to content
Siglata Docs
English
Esc
navigateopen⌘Jpreview
On this page

Files

Upload, organize, and recover organization files.

Every file in Siglata belongs to an organization. Files remain with the organization when its members change. The storage architecture incorporates pre-allocated upload reservations, fixed 8 MiB multipart chunking, atomic metadata operations, and an automated 30-day trash recovery lifecycle.

Storage Quota Architecture

Each organization starts with a baseline storage quota of 10 GiB (10,737,418,240 bytes).

Siglata tracks storage through an atomic, transactional ledger that distinguishes between retained data and reserved upload capacity:

┌────────────────────────────────────────────────────────────────────────┐
│                   Total Organization Quota (10 GiB)                    │
├──────────────────────────────────────┬──────────────────┬──────────────┤
│              Used Bytes              │  Reserved Bytes  │  Available   │
│ (Active Files + 30-Day Trash Files)  │ (Active Uploads) │  Free Space  │
└──────────────────────────────────────┴──────────────────┴──────────────┘
  • limitBytes: Total storage capacity allocated to the organization (10,737,418,240 bytes).
  • usedBytes: Retained storage across both active files and files in trash. Moving an item to trash does not free quota immediately; bytes remain accounted for until the 30-day recovery period lapses and cleanup purges the data.
  • reservedBytes: Storage locked by in-flight multipart uploads. When an upload begins, Siglata reserves the declared file size upfront to prevent concurrent uploads from colliding or exceeding organization limits.
  • Available Space: Calculated in real time as limitBytes - usedBytes - reservedBytes.

Multipart Chunking & Upload Reservations

To support massive files with high transfer reliability across unstable connections, Siglata uses a fixed 8 MiB chunking pipeline:

Parameter Specification Value
Chunk Size (CHUNK_SIZE) Fixed part size 8,388,608 bytes (8 MiB)
Maximum Part Count Maximum parts per upload 10,000 parts
Maximum File Size (MAX_FILE_BYTES) Upper limit per single file 83,886,080,000 bytes (~80 GB)

The Upload Lifecycle

1. upload_begin ──> Check Quota ──> Pre-allocate reservedBytes ──> Return Upload ID & URL


2. PUT /parts/{n} ──> Upload 8 MiB Chunks (Parallel or Sequential) ──> Record receivedParts


3. upload_complete ──> Verify Part Count ──> Convert reservedBytes to usedBytes ──> File Active

        └── (If Aborted) ──> upload_cancel ──> Delete Chunks ──> Release reservedBytes
  1. Upload Reservation (upload_begin):

    • The client provides a unique requestId (UUID), name, mediaType, and size.
    • Siglata verifies that size <= (limitBytes - usedBytes - reservedBytes).
    • The declared bytes are atomically added to reservedBytes, and an upload session is created with an expiration timestamp.
    • The server returns an upload identifier and transfer instructions containing the HTTP PUT URL template.
  2. Chunk Transmission (PUT /v1/mcp/uploads/{uploadId}/parts/{partNumber}):

    • The client streams parts numbered sequentially from 1 to N (up to 10,000).
    • Each part must be exactly 8,388,608 bytes, except for the final part which sends the remaining declared bytes.
    • Parts can be uploaded concurrently. The server validates each chunk’s length and records its arrival in the upload manifest.
  3. Sealing & Activation (upload_complete):

    • Once all parts have been received, the client calls upload_complete.
    • The server verifies that every part from 1 to N is accounted for and that the total uploaded size matches the reservation.
    • The upload record transitions to completed, the file is marked active, and the reserved capacity moves from reservedBytes into usedBytes.
    • This operation is completely idempotent: retrying upload_complete with the same upload ID returns the active file record safely.
  4. Cancellation & Expiration (upload_cancel):

    • If an upload is cancelled by the user or client, upload_cancel triggers cleanup of any stored chunks and immediately releases the reservedBytes.
    • If a client disconnects unexpectedly, background reconciliation automatically detects expired upload sessions, releases their reservations, and cleans up orphaned chunks.

30-Day Trash & Recovery Lifecycle

Siglata implements a safety-first data retention model to protect teams against accidental file deletion:

Moving to Trash (file_trash)

When a member deletes an active file:

  • The file’s status transitions from active to trash.
  • The timestamp of deletion is recorded (trashed_at = clock_timestamp()).
  • The recovery deadline is set to exactly 30 days in the future:
    recover_until = clock_timestamp() + interval '30 days'
  • The file disappears from the default files list but appears in the trash view (files_list with state: "trash").
  • Quota Accounting: The file’s bytes remain charged to the organization’s usedBytes. This guarantees that the stored data is fully preserved and that restoring the file will never fail due to quota exhaustion.

Restoring Files (file_restore)

If a file was deleted accidentally:

  • Any member with files:write permissions can invoke file_restore at any point before recover_until.
  • The file atomically returns to active status, clearing trashed_at and recover_until.
  • Because the file’s bytes were already accounted for in usedBytes while in trash, restoration consumes zero additional storage quota.

Automated Permanent Purge

  • Once the 30-day recovery deadline passes (recover_until <= clock_timestamp()), restoration is permanently disabled.
  • The Siglata background reconciliation worker queries for expired trash items in batches:
    SELECT id FROM files_object
    WHERE state = 'trash' AND recover_until <= clock_timestamp()
  • The worker marks the object for purging, deletes the stored binary blobs from the object storage tier, and cleans up the database record.
  • Only after binary deletion is confirmed are the file’s bytes permanently subtracted from the organization’s usedBytes, freeing up quota for new uploads.

Metadata Operations

File Renaming (file_rename)

Renaming a file in Siglata updates only the database record’s name attribute. Because stored object blobs are addressed by immutable UUIDs, renaming is an instantaneous, zero-cost operation that requires no byte copying or quota adjustment.

Streaming Downloads (file_download)

Authorized members can download files directly via the authenticated download endpoint (GET /v1/mcp/files/{fileId}/download). The endpoint validates the caller’s active organization membership in real time before streaming bytes, ensuring that revoked members or former collaborators cannot access organization assets.

Folders and Access Control

Files can live in nested folders, and every file and folder carries a visibility flag:

  • org (default): Every organization member can read and write the object, subject to their OAuth scopes. This preserves the behavior of all files created before folders existed.
  • restricted: Only the object’s creator, organization owner/admin members, and members holding an explicit grant can access the object.

A restricted folder restricts its entire subtree: to read or write an object, the caller must satisfy every restricted folder in its ancestor chain. A grant on a folder extends to its unrestricted descendants, while a restricted object inside a shared folder still requires its own grant.

  • Denied operations fail with the forbidden error code; restricted objects a member cannot read are also omitted from files_list and folders_list results.
  • grant_create and grant_revoke are limited to the object’s creator and organization administrators. To change a grant level or grantee, revoke then create (there is no separate replace operation).
  • file_set_visibility and folder_set_visibility require write access on the object; they do not change existing grants.
  • file_move and upload_begin into a folder require write access on the destination folder.
  • Trashing a folder does not trash its contents; when a trashed folder passes its recovery deadline, it is deleted and its children move to the organization root.

Was this page helpful?