Tidenda

Concepts

Media

Image upload model, format and quota rules, rights and AI provenance, signed bytes.

Media

Tidenda stores tenant-uploaded images as first-class documents: one core/image per image, with the bytes in object storage and the metadata, rights, and provenance in a collaboratively-edited document. This page describes the contract integrators meet - what an upload looks like, what formats are accepted, how rights and AI provenance are modelled, and the read surface for downstream consumers.

What an image is

An image in Tidenda is one document plus one set of bytes. The document carries the editorial metadata (caption, alt text, copyright, photographer, restrictions, AI provenance, the signing record) and lives in the same workflow machinery as articles and planning items. The bytes live in tenant-scoped object storage and never cross a tenant boundary. The document references the bytes by stable URL.

Re-uploading edited bytes produces a new document. There is no in-place byte replacement and no destructive edit. If you want a cropped or colour-corrected variant, that is a separate image with its own id, its own signature, and its own rights record.

Upload model

Uploads go directly to object storage. The client requests a short-lived signed PUT URL from the platform, uploads the bytes straight to that URL, then confirms the upload by posting the extracted metadata. Bytes never traverse the platform's API servers.

The flow has four steps:

  1. Allocate. Client posts an intent (filename, mimeType, size, contentHash, declared variants) to the upload-request endpoint. The platform enforces format and quota, hands back an image id plus signed PUT URLs for the original and each declared variant. A signed URL expires within minutes - it's not a long-term handle.
  2. Upload. Client PUTs the bytes to the signed URLs. Failed PUTs can be retried by requesting a fresh URL; partial uploads cost nothing on the platform side.
  3. Finalize. Client posts the extracted metadata (EXIF / XMP / IPTC fields, dimensions, content hash, optional C2PA manifest) to the finalize endpoint. The platform creates the core/image document, indexes the dedup row, and increments the tenant's storage tally.
  4. Sign. The platform signs the original bytes with the tenant's signing key and writes the signature alongside the bytes. The signature also lands on the document's meta.signature. See Signing.

If a finalize arrives without the full set of derived variants (thumbnail, preview, delivery), a background worker decodes the original and backfills the missing variants. The document is marked processingStatus: 'pending' until the worker completes.

Deduplication

Each image carries a SHA-256 hash of the original bytes (meta.contentHash). Within a single tenant, a hash collision short-circuits the upload: the allocate response returns the existing image's id with isDuplicate: true and no PUT URLs. The caller can link the existing id to additional assignments without uploading bytes a second time.

Hashes do not cross tenant boundaries. Two tenants holding the same bytes hold two separate documents under two separate storage prefixes.

Supported formats

Format MIME Accepted
JPEG image/jpeg yes
PNG image/png yes
WebP image/webp yes
AVIF image/avif yes
GIF image/gif yes
HEIC / HEIF image/heic, image/heif yes
TIFF, camera RAW (image/x-canon-cr2, ...) no

HEIC support is part of the contract - phone uploads work without an intermediate transcode. TIFF and RAW are intentionally rejected to keep storage and processing predictable; convert upstream and submit the result.

Caps

Cap Default
Per-image size 75 MB
Per-tenant total storage 100 GB
Files per upload batch 50

The per-tenant cap is administrator-managed. A tenant cannot raise its own cap; contact the platform operator.

Variants

Each image carries up to four variants in object storage. The original is the source of truth; the others are derived for faster reads.

Variant Width Format Purpose
original source source The bytes the rights record covers.
thumb 256w WebP List rows, picker tiles.
preview 1024w WebP Editor figures, modal previews.
delivery source JPEG Downstream publishing path.

The browser-side upload pipeline normally produces thumb, preview, and delivery during decode; HEIC or any decode failure falls back to a server-side worker, which fills the gaps from the original. Until variants land, the document's meta.variants array is the source of truth for "which variants exist right now".

Reading bytes

Bytes are reached through a stable URL pattern:

GET /api/images/<id>/<variant>

The platform responds with a 302 redirect to a short-lived presigned URL on the underlying storage. The redirect target expires within minutes; clients should follow the redirect immediately, not cache it. The /api/images/<id>/<variant> URL itself does not expire.

Anyone authorised against the owning tenant can read any variant. Cross-tenant reads are refused at the auth layer before a presigned URL is issued.

Rights model

Three structured fields capture image rights:

Field Maps to Used for
copyright IPTC dc:rights Attribution line ("(C) 2026 Jane Doe").
instructions IPTC photoshop:Instructions Provider directives ("Free for editorial use during Q2 2026.").
usageTerms IPTC xmpRights:UsageTerms Formal terms ("Editorial use only. No derivatives.").

Plus a server-computed flag:

Field Value
restrictions true when instructions is set, or usageTerms is set, or aiGenerated is true.

The editor and the media archive surface a warning marker on any image where restrictions is true; the hover popover shows the underlying instructions and usageTerms text. Integrators that surface images downstream should mirror this treatment - the editorial intent is to make restrictions visible at the moment of use, not hidden in a sidebar.

Provenance

AI generation

meta.aiGenerated is a tri-state:

Value Meaning
true Image is AI-generated. UI surfaces a persistent badge.
false Explicitly disclaimed.
absent Unknown.

The platform sets aiGenerated: true from incoming metadata or C2PA assertions; tenants can also flip the flag manually. The flag propagates into the computed restrictions so a warning attaches by default even when no rights text accompanies it.

C2PA

The platform preserves C2PA manifests that accompany an upload but does not issue its own. A preserved manifest is recorded under meta.c2paManifest with the original issuer and claim generator (free text - the platform does not maintain a trust list for C2PA issuers). The raw manifest is stored alongside the bytes for downstream verifiers that want to re-validate the chain.

Tidenda signatures

Independent of any C2PA chain, the platform signs the original bytes with the tenant's signing key. The signature lives on meta.signature (alg, keyId, sig) and as an original.sig sidecar in storage. Verification follows the same recipe as snapshot signatures with one change: the verified bytes are the original image bytes prefixed with the domain separator "void-image-v1\0". See the signing guide.

GDPR and deletion

Concern Default
GPS in EXIF Stripped from the delivery variant by default. The original retains it for the rights record.
Hard delete Available to organisation administrators only.
Tenant purge Removes every image's bytes, document, dedup row, and signature on tenant teardown.

There is no "delete bytes but keep the record" mode. Deleting an image deletes everything attached to it; downstream consumers should treat the snapshot they signed against as the durable historical record.

Document shape

For the wire shape, see core/image in Document formats.

Related pages

  • Document formats - the envelope and other types.
  • Signing - signature verification for both snapshots and original-byte signatures.
  • Webhooks - events for the core/image document. There are no separate "image upload" events; the document's transitions emit the same shape any other document type does.
  • Security - tenant isolation, signing-key custody, deletion guarantees.