Skip to content
24/48h shipping across Italy
Skip to content
Documentation navigation

k0smos Data Exchange Package Specification

This document defines the public k0smos.data_exchange format version 1. It is the interoperability contract for content moved between k0smos tenants.

Transport forms

Content-only packages may be a single UTF-8 JSON document with extension .k0sdata.json. Packages carrying binary media should use the ZIP transport with extension .k0sdata:

manifest.json
checksums.json
signature.json                 # optional
entities/{entity-code}.json
media/{sha256}.{extension}     # optional

YAML and CSV are not format-v1 transports. Readers detect ZIP by its magic bytes, not by the uploaded filename.

Canonical JSON envelope

{
  "format": "k0smos.data_exchange",
  "format_version": 1,
  "generator": "k0smos/0.21.0",
  "generated_at": "2026-07-20T00:00:00+02:00",
  "locales": ["en", "it"],
  "entities": {
    "widget": {
      "schema_version": 2,
      "records": [{"key": "home|en|Hero|10"}]
    }
  },
  "checksums": {
    "widget": "<sha256 of the canonical entity document>"
  }
}

Object keys are recursively sorted as strings. List order is retained. JSON is encoded with unescaped Unicode and slashes; exports sort records by logical key. Checksums are lowercase SHA-256 hex strings. The reader requires an exact checksum index: missing and orphan checksum entries are rejected.

ZIP manifest.json declares every entity file, schema version and record count. checksums.json must exactly cover every declared entity and media file. Any undeclared archive entry, duplicate entry, traversal path, oversized entry, excessive compression ratio or checksum/count mismatch rejects the package.

Logical identity and references

Tenant-local integer IDs must never be exported. Current entity identities and dependency order are:

Order Entity Logical identity
5 app_setting allow-listed setting key
10 widget hook, locale, title, sort order; fixture packs may declare a bounded insert-only match strategy
20 page type, slug, locale
30 blog base slug; localized content is stored in translations{locale}
35 tax_rate tax code
40 category slug; parent reference is a category slug
50 product SKU; category and tax references are slug/code
60 product_variant product SKU plus variant SKU
70 product_image product SKU plus deterministic per-product slot

The core app_setting provider is deny-by-default. Format v1 currently allows the reviewed public identity key company.contact_email and the explicit social-platform keys declared by PortableAppSettingDataExchangeProvider; it does not accept arbitrary company.* or social.* prefixes. app_setting schema v2 additionally accepts match_strategy: "empty_as_missing" only for company.contact_email and only changes insert-missing behavior: a blank schema placeholder is filled, while a non-empty destination value is preserved. All other records use logical_key.

Generic cross-record references use {"$ref":"entity:logical-key"} when a provider declares them. Media references use a checksum handle and are rebound to a destination Media row; the original tenant Media ID never travels.

Media

JSON media entries contain metadata plus content_base64; ZIP media entries contain metadata in the manifest and raw bytes under media/. The map key and file checksum must equal the SHA-256 of the raw bytes. Each binary is limited to 16 MiB and the complete ZIP to 128 MiB. Only image and PDF media are accepted by the Media gateway. Imports deduplicate by checksum, preserve visibility, rewrite declared IDs/URLs/embedded /media/{id} references, and clean newly-created media when the owning import aborts. Successful import/export packages are archived privately through Media when that module is active.

Signatures

Signatures are optional Ed25519 detached signatures. JSON signs the canonical envelope without its signature member. ZIP signs the canonical object {"manifest": ..., "checksums": ...} and stores the result in signature.json:

{"algorithm":"Ed25519","key_id":"deployment-key","signature":"<base64>"}

Readers reject malformed, invalid or untrusted signatures. Deployments may require a trusted signature. Signing secrets are environment-only and never stored in tenant settings, packages, logs or queue payloads:

  • K0SMOS_DATA_EXCHANGE_SIGNING_KEY_ID
  • K0SMOS_DATA_EXCHANGE_SIGNING_SECRET_KEY (base64 Ed25519 secret key)
  • K0SMOS_DATA_EXCHANGE_TRUSTED_PUBLIC_KEYS (JSON key-id → base64 public key)
  • K0SMOS_DATA_EXCHANGE_REQUIRE_SIGNATURE (true/false)

Run history records signature status and key ID, never key material.

Import semantics

Modes are validate_only, preview/dry-run, insert_missing, update and replace. insert_missing is the default. Conflict policies are preserve, overwrite and fail. Preview retains the selected write mode and reports the exact creates, updates, deletes, skips and conflicts while rolling back every write.

replace is authoritative only for entity types present in the package and for the selected locales. It upserts in dependency order, then deletes missing rows in reverse order in one package transaction. It requires data_exchange.manage and confirmation of the checksum returned by an exact-file preview. Import-locked catalog rows, referenced parents/tax rates and out-of-scope locales remain protected.

Rich-text fields are validated before providers run. Active browser content such as scripts, event attributes, executable URL schemes and unsafe CSS is rejected. Diagnostics and durable reports are bounded and content-redacted.

Translation

Descriptors opt fields into plain, rich-HTML or GrapesJS translation. Stable keys, URLs, attributes, CSS, scripts, placeholders, SKU, currency and topology are never translated. Locale-on-record entities and nested translations{locale} catalogs are supported. Existing human targets without machine provenance are preserved unless explicit retranslation is requested. Provenance records source checksum/locale, target locale, provider/model, timestamp and estimated character/token usage; credentials and full prompts are never persisted.