Skip to content
Strata is pre-1.0. APIs, protocol, and storage format may change.

Architecture

The Strata workspace separates each responsibility into one package.

packages/
├── strata_protocol/ # WebSocket message types and JSON conversion (both)
├── strata_document/ # Typed LWW-register schemas (target: both)
├── strata_server/ # mist + beryl + shelf (target: erlang only)
├── strata_client/ # Sans-IO client state machine (target: both)
├── strata_component/ # Typed headless component contracts (target: both)
├── strata_transport/ # Browser WebSocket transport (target: javascript)
├── strata_transport_gun/ # Gun WebSocket transport (target: erlang)
└── strata_admin/ # Admin page (target: javascript only)
strata_protocol (no strata deps)
strata_document (no strata deps)
strata_server → strata_protocol
strata_client → strata_protocol, strata_document
strata_component → strata_client, strata_document
strata_transport → strata_client
strata_transport_gun (no strata deps; uses gluegun)
strata_admin → strata_client (via JS target)

Strata sends versioned JSON messages over WebSocket. The client and server both use strata_protocol to convert these messages to and from JSON. This keeps the message types consistent.

Client → Server: join, leave, delta, create, delete, presence_set, ping Server → Client: welcome, snapshot, delta, deleted, presence_state, presence_diff, error, pong

  • Root type: an ORMap from lattice_maps.
  • strata_document provides optional typed fields and record schemas for an ORMap that contains LWW registers.
  • One store actor owns all document state.
  • Beryl owns each socket and document-topic join.

The current server is single-node. Its store owns document state, deletion links, and tombstones for that instance, and its PubSub scope is node-local. CRDT merging between clients does not provide server-to-server replication. Connecting BEAM nodes or enabling distributed PubSub alone would not coordinate store ownership, checkpoints, or atomic create/delete operations. Multi-node support remains deferred in #6. See single-node deployment before running independent instances.

An app can model several document kinds and link them by id: one document (a composite) holds typed references to others. create and delete are serialized in one store-owner turn across the parent and a child; delete cascades to every descendant. See Composing Documents.

TermMeaningWho records it
ReferenceAn application field names another document ID. It grants no deletion authority or event-routing claim.Application CRDT state
Deletion owner / parentThe single recorded parent of an owned child. A delete through this parent removes the child and its recorded descendants.Server create and checkpoint
Event-routing ownerThe one component instance that receives a document's events in a host.Host routing index
Application references: workspace --> board --> card
shortcuts -----------> card
Server deletion tree: workspace --> board --> card
shortcuts (no deletion link to card)
Host routing index: board --> Board instance
card --> Board instance
shortcuts --> Shortcuts instance

Deleting board removes card, even though shortcuts still references it. The remaining reference dangles. The host routes the card's deleted event to its Board instance; the event-routing claim did not grant deletion rights. References can cross deletion subtrees. The server does not derive deletion links from CRDT fields.

Use Create(parent, child, ...) for a new owned child. To reference an existing document without taking ownership, write its ID into application state with a normal document edit. Do not send Create for that target. An owned child has exactly one deletion parent; an unparented root has none.

DocId(tag) provides compile-time schema separation. Serialization retains the string ID, not the phantom tag. doc_id does not validate an incoming runtime ID, check its stored schema, or authorize deletion. Application decoders and host routing checks remain necessary.

See the host-author contract for event-routing rules and persistent deletion identity for tombstone retention and the ban on deleted-ID reuse.

strata_component packages a collaborative feature as a typed headless definition. A definition contains config codecs, initial state, local updates, replicated event handling, typed outputs, and an event-routing ownership query.

Typed output ports, input ports, and bindings define compiler-checked integration points between components. The application host owns the shared connection, routes events by document ID, handles component outputs, and mounts UI adapters. The package does not own a socket, storage, presence, or a UI framework.

The current workspace example uses one browser host. The host owns one WebSocket connection, one root PageStore, a dictionary of component models, and a document-id routing map. The host routes each document event to the component that claims that id for routing. Components return client commands for the host to send. Local updates can also return typed outputs.

The host uses closed sum types for supported component kinds and bindings. It does not use a runtime component registry. Its direct workflow bindings exist only in the current browser session and run best-effort. Closing or crashing the browser loses routes and pending work; a disconnect can leave sent commands with unknown outcomes. The server does not resume workflow work. The package does not include runtime discovery, a persisted connection graph, or durable intent. See the workflow delivery boundary.

  • Join and reconnect: The server sends a snapshot with encoded ORMap state.
  • Steady state: Applications send encoded ORMap state in delta frames. The store validates and merges the state. The channel sends accepted merged state to other sockets with beryl.broadcast_from. Each peer must merge that state into its local document.

Strata v0 reads one shared secret from STRATA_TOKEN. The client sends the token as ?token=<secret>. The server checks it before the upgrade completes. The wire protocol does not have an auth frame.

beryl stores presence for each document. strata_protocol defines the presence data. It can include a cursor, selection, name, and color.

One store actor holds document state, deletion parent links, and tombstones. Shelf saves them together in an atomic store.dets checkpoint. Recovery validates ORMap state and deletion links before the server starts. Acceptance precedes persistence; see Durability and Recovery.