You cannot change modality later. Create a new dataspace if the contract is wrong.
People often say telemetry for the
timeseries modality. The API value is timeseries.
document and vector are the content modalities: files, and the searchable text pulled out of them. Both carry a platform-owned set of columns you cannot change or remove. A document dataspace is hybrid on top of that, so you can attach fields of your own to a file through a metadata object; a vector dataspace is typed, because every search filter has to be a real indexed column. Pulling text out of a file is opt-in per file. See Document and Vector.Guides
Telemetry
Append-only named fields. ClickHouse MergeTree. API
timeseries.Point
Append-only sparse metric bags. Uniform JSON map. Can cold-store from create.
State
Current document. Postgres, HTTP row CRUD, guaranteed events.
Mutable
Current table. ClickHouse ReplacingMergeTree, tombstones.
Document
One row per file. Presigned upload, content-addressed, list and download. Indexing opt-in.
Vector
One row per chunk plus its embedding. Hybrid semantic and keyword search.
Schema and layouts
jsonb / hybrid / typed / map, field types, promotion, proposals.
Storage
Engine, fast vs cheap, hot vs hot_cold, and the valid combination matrix.
Choose a modality
Ask these in order:- Is it a file, or prose you want to search by meaning? A file → document. The text pulled out of it, searched semantically → vector. Pair them when you want files searchable; a document dataspace on its own is a perfectly good file store.
- Will this row ever be updated or deleted? No → telemetry or point.
- Is each sample a fixed (or soon-fixed) set of named fields? Yes → telemetry. A sparse bag of metric names that varies per device or firmware → point.
- Is there one current document per source, and do you need HTTP row CRUD, downsync, or a change event that cannot be lost? Yes → state.
- Is it a many-row current table keyed by a business primary key? → mutable.
UPDATE … WHERE status = 'running'), leases, or a job state machine, that is ordinary platform data — not a dataspace.
Modality × layout × storage
Full rules: Schema and Storage. Compact matrix:cheap is Parquet-only (no hot table). hot_cold is a fast hot table plus an aged-out Parquet tier. They are not interchangeable. hot_cold + cheap is rejected. Document and vector take neither: a document’s bytes already live in object storage, and an embedding has no time axis to age along.
At a glance
Layouts (summary)
Layout is schema shape, not storage class. Details and field types: Schema and layouts.
Telemetry climbs
jsonb → hybrid → typed. Point stays map. State does not auto-promote. Mutable and document allow hybrid and typed only. Vector is typed and fixed. On both content modalities the platform owns the column set — the fields you send at create are replaced, not merged — but a hybrid document dataspace still absorbs fields of your own into overflow.
Identity and meta columns
Every row is associated with a source (usually a device). The platform adds meta columns; you do not declare them as user fields.source_id is which producer wrote the row, not your business key. A SKU, machine id, or OPC-UA node belongs in natural_key (or in a user field). Hashing a business key into source_id makes the row unaddressable by the thing it describes.
Writes
All row writes go through one write plane. Producers encode a batch (MQTT, edge sync, HTTP, workers). A durable per-project buffer is the no-loss commit point. The write plane then normalizes against the catalog and persists to ClickHouse or Postgres.- Known fields land in typed columns.
- Surprise fields land in overflow when the layout has one.
- Surprise fields on a typed layout go to the per-project orphan table (kept, not deleted) for review.
event_tstoo far in the future (more than one day ahead) goes to the per-project dropped-rows table.event_tsolder than the hot window is dropped as late only when tiering ishot_cold. Hot-only dataspaces accept arbitrarily late history.
version that is not newer than what is already stored.
Document files are the exception to the shape, not to the plane: you upload bytes straight to object storage through a presigned URL, and the row that describes them is written the same way every other keyed row is. Chunking and embedding a file is opt-in per registration (vectorize: true) and produces ordinary rows in the paired vector dataspace.
Reads
- QueryScript and the query gateway use the dataspace name. Do not put physical table names in documents — those are rejected.
- SQL (
POST /projects/{project_id}/dataspaces/query) is read-only and runs against the dataspace read view. The catalog fieldread_viewis informational; copy the name from the catalog if you use raw SQL. - HTTP row CRUD (
…/dataspaces/{id}/rows) covers the keyed Postgres modalities: state, document, and vector. Telemetry and point have no current-row identity. Mutable does not offer GET-after-PUT. - Document reads (
…/dataspaces/{id}/documents) list a document dataspace, read one file’s record, and mint a short-lived download link. Document only, and the surface to prefer over raw rows. See Document. - Semantic search (
POST …/dataspaces/{id}/search) is vector only. See Vector. - Authorization is per dataspace (
can_read_data/can_write_data). A caller without read grant does not see the table.
POST …/dataspaces/{id}/shares).
Change events
Hard-real-time safety (for example an e-stop) must still trip on the device. The platform records and propagates the change; it is not a substitute for a local safety loop.
Edge SQLite sync
Attaching a sync policy provisions an ordinary dataspace — one per device table, shared across devices in the project. Rows are keyed bysource_id = device id.
point is a cloud create choice. Edge attach does not auto-map to it.
Only state and mutable may carry an edge_sqlite sync target. Telemetry and point are upsync-only.
Omega’s on-device table_strategies (rows / telemetry / ignore) is how data leaves the device. The table above is how the cloud replica is stored. strategy: rows in Omega becomes a mutable dataspace on attach, not state. Use a state / kv policy strategy when the table is one document per device.
See Capture strategies and Edge data sync.
Create a dataspace
$API is the platform base URL (production: https://api.ilyama.golain.io/core/api/v1).
Optional body fields: storage_class (fast / cheap), tiering (hot / hot_cold), layout, fields, natural_key, sync_targets. Which combinations are legal is the storage matrix.
Vector requires embedding_model, embedding_dims, and one credential field. Document optionally takes chunk_dataspace_id, and needs it only if you intend to register files with vectorize: true. All of them are fixed at create.
Interactive create, list, query, schema, shares, and row CRUD live under HTTP API → Dataspaces in the API reference.