Skip to content

Storage accounts

A storage account is a place where the File Service stores bytes. The platform storage (default) holds every tenant’s files until you give a tenant storage of its own. This page is for platform administrators: it covers the Storage accounts page of platform administration and the routes behind it. What tenants notice (almost nothing) is on Where files are stored.

The page lists every account, default first, with its kind, location, status and the number of tenants assigned to it.

Kind What you enter
A bucket The bucket, its region (auto for stores without regions), the endpoint of the object store (empty: the store’s own default), path-style addressing (most compatible object stores need it), an optional public URL for public files (a CDN in front of the bucket), and an access key id and secret
A directory A directory of the servers the service runs on, inside a root the operator allowed. Only where the platform allows directories; elsewhere storage_adapter_not_allowed

Saving probes the account first. The service writes, reads, signs and deletes a small probe object in it, and saves the account only when that worked; otherwise the answer is storage_account_verification_failed with the store’s own error message. Verify runs the probe again and records the outcome: an account whose last probe failed (status: failed, with last_error) takes no new tenant and no move (storage_account_not_verified).

  • The secret key is stored encrypted and never shown again: the page shows that keys are set and the last four characters of the key id. Rotating the keys is a change of the account, probed before it is saved.
  • Two accounts never share a location (storage_account_in_use): a move between them would delete what it copied.
  • The name can change at any time; the location only while nothing uses the account.
  • Remove works only for an account that no tenant, file version, open upload or move uses (storage_account_in_use otherwise). It forgets the account; it never deletes the bytes in the bucket or directory.
  • default is the platform’s own configuration: it cannot be changed or removed here.
  • Browsers and apps upload straight to a bucket and read every part’s ETag from its answers. A bucket account therefore needs cross-origin rules that allow PUT from the tenant’s app origins with the ticket’s headers and expose ETag, as the platform storage does. The probe does not check them: try an upload from the tenant’s app before you move its files.

Choose a tenant to see its assigned account, where its new objects go (the assigned account, or a running move’s target), and how many of its versions and bytes live in each account.

Assigning a tenant to an account changes only where its new files and versions go. Its existing files stay where they are and keep being served from there. To bring them along, move them.

  1. Start. Choose the target account and start the move. The tenant’s new files go to the target at once.
  2. Copy (phase: copying). Every version of the tenant on another account is copied to the target, checked by size and checksum, and then served from the target. A version still uploading or processing waits for its turn (versions_waiting).
  3. Verify (verifying). Every copy is read back from the target and compared with the original’s checksum; a missing or damaged copy is copied again.
  4. Switch and wait (waiting). The tenant’s account becomes the target (switched_at). The old copies stay until every URL signed against them has expired (delete_after).
  5. Delete (deleting, then done). The old copies are deleted, each only once the target holds it.

The move follows progress: versions_total, versions_moved, objects_copied, bytes_copied, objects_verified, objects_deleted and versions_waiting. One move per tenant runs at a time (storage_migration_in_progress). A move that fails repeatedly stops with status: failed and an error; the tenant’s new files go to its assigned account again, files already moved stay readable where they are, and a new move continues from there.

Throughout, file ids, versions, permissions and share links stay the same, downloads and uploads keep working, and files under a legal hold move like any other. Only a public file’s public_url changes: tell the tenant to read it from the file again rather than keep it. Moving back to default works the same way.

Route Does
GET /platform/storage-accounts, GET /platform/storage-accounts/:storage_account_id The accounts, or one (credentials never included)
POST /platform/storage-accounts Adds one: { name, adapter, settings, credentials } (a bucket needs credentials: { access_key_id, secret_access_key }; a directory settings.root and adapter: filesystem)
PATCH /platform/storage-accounts/:storage_account_id Renames it, rotates its keys, or changes its location while nothing uses it (settings merge)
POST /platform/storage-accounts/:storage_account_id/verify Probes it again; answers the account with probe: { ok, error, duration_ms }
DELETE /platform/storage-accounts/:storage_account_id Removes an unused account
GET /platform/tenants/:tenant_id/storage-account, PUT /platform/tenants/:tenant_id/storage-account A tenant’s storage; assigns it ({ storage_account_id }, default or null for the platform storage)
POST /platform/tenants/:tenant_id/storage-migrations Starts a move ({ target_storage_account_id }, 202 with the move)
GET /platform/tenants/:tenant_id/storage-migrations, GET /platform/storage-migrations/:migration_id A tenant’s moves, newest first; one move with its progress

They take a platform administrator’s user token, or a machine token with files:config.manage of a client of the Files platform application itself; every other caller gets platform_admin_required. The ccs-files-client library has them as platform.storage (ccs-files-client). Changes count against the settings rate limit. An account the service cannot reach answers 503 storage_unavailable on every route that needs it.

Every change is audited with the administrator, never with a credential: storage_account.created, storage_account.updated, storage_account.verified, storage_account.deleted, tenant_storage.assigned, and for a move storage_migration.started, storage_migration.switched, storage_migration.completed and storage_migration.failed. See Audit actions.