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.

Audio

Audio recordings are a first-class media type, core/audio. The model parallels images: one uploaded file becomes one document, tenant-scoped SHA-256 dedup keeps repeat uploads to a single doc, transitions signal editorial state, snapshots capture immutable versions, and originals carry an Ed25519 signature. What differs is the byte format, the processing pipeline, and the transcript that sits on top of the audio.

Accepted formats: MP3, WAV, M4A (AAC), WebM, Ogg-Opus, FLAC. Per-file cap is 500 MB; per-tenant cap is 500 GB. The client hashes and uploads the bytes byte-for-byte; no re-encoding.

Processing pipeline

An uploaded audio doc starts at processingStatus: 'pending'. Transcription and diarization run automatically; the state machine advances through transcribing (speech-to-text), diarising (speaker attribution), then lands at ready. On any pipeline failure the doc transitions to failed with a human-readable processingError, and an editor can retry from the transcript view. Deployments that opt out of diarization skip that leg and go straight to ready after transcription; segments still land with no speakerId.

Transcript segments are time-aligned to the audio timeline (startMs, endMs) and carry the recognised text, an optional speakerId when diarization ran, and a per-segment signature after an editor "verifies" the text (see Signing).

Rights

Same three-field model as images. recordist is the audio parallel to photographer: the person who captured the recording. credit carries the agency or wire. copyright, instructions, and usageTerms behave identically to their image counterparts, and restrictions is a live-derived flag driven by the same rules.

Reading bytes

Same readUrl pattern as images: retrieving the original bytes resolves to a short-lived signed storage URL at request time. The signature over the bytes uses a distinct domain prefix ("void-audio-v1\0") so an audio signature cannot be replayed as an image signature. See Signing.

Signatures

Two signature kinds:

  • Whole-file — over the original bytes under the "void-audio-v1\0" domain. Written at upload finalize.
  • Per-segment — over a canonical serialisation of one transcript segment under the "void-audio-segment-v1\0" domain. Written when an editor clicks Verify on the segment. Segments carry a signedTextHash alongside the signature so consumers can detect whether the current text still matches the bytes that were signed; a mismatch means the segment was edited after verification and needs re-verifying.

Segment signatures live on the segment record itself, not in webhook payloads. Whole-file signatures are shipped in the embeddedAudioAssets roll-up on outbound webhooks; see Webhooks.

Deletion

core/audio follows the same deletion path as core/image. A soft delete keeps the bytes for a grace window in case an integrator still holds a snapshot reference; a hard delete (owner or admin only) removes the bytes, the signature sidecar, the dedup index row, and the storage tally.

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.