Tenants, key domains and datasets
These identifiers and structures appear throughout the SDK API. Every namespace works with them.
Identifiers
| Type | What it is |
|---|---|
TenantId | Immutable. Device certificates (cards), stored objects and evidence carry it for the tenant’s whole lifetime. |
RecipientId | Sixteen bytes of SHA-256 over a device’s public key, base64url-encoded. Every part of the SDK names a device by its RecipientId, including shares, cards and access events. |
Locator | The opaque id of a record, a file, a folder or a key domain root. It stays the same across every version of the object it names. |
EventId | An access event, assigned by the Seald Healthcare Cloud. Every Decided<T> carries one, whatever the decision. |
Bytes | Raw bytes: Uint8Array in TypeScript, Data in Swift, ByteArray in Kotlin. |
Seconds | A duration: a number of seconds in TypeScript, TimeInterval in Swift, Duration in Kotlin. |
People, groups and roles
Person is how the identity provider names someone, never a name or an email address your
application would have to protect separately:
interface Person { iss: string; sub: string;}struct Person { let iss: String let sub: String}data class Person( val iss: String, val sub: String,)iss and sub are the issuer and subject of the identity token, as the identity provider set
them. The SDK treats these two strings as the whole identity of a person. Nothing else about them
passes through the SDK API.
A Group is a group as the identity provider names it, a plain string. Groups let a tenant share a
key domain with everyone in a group at once. When a person joins the group later, a member device
gives them access. No new share is needed.
Role fixes four names and leaves the rest to the tenant:
type Role = 'owner' | 'admin' | 'employee' | 'contractor' | string;typealias Role = String// fixed roles: "owner", "admin", "employee", "contractor"typealias Role = String// fixed roles: "owner", "admin", "employee", "contractor"owner, admin, employee and contractor carry meaning the SDK and the Seald Healthcare Cloud both act on.
The Owner role can unshare any key domain. Only an Owner or Admin can approve certain changes with
a fresh multi-factor sign-in. The Owner role is not the same as being a domain owner. Only a domain owner can share their
key domain. The tenant creates any other role itself. Such a role has no
special behavior in the SDK.
Classification is the sensitivity of a dataset or a field:
type Classification = 'phi' | 'pii' | 'public' | 'de-identified';enum Classification { case phi, pii, `public`, deIdentified }enum class Classification { PHI, PII, PUBLIC, DE_IDENTIFIED }phi is protected health information. pii is personal information that is not health data.
public carries neither. de-identified is data a tenant has stripped of both under its own
process. The classification travels with a dataset’s registration and with a record’s segment
fields. It shapes what a policy may decide about the data.
Cards
A Card is a device certificate, signed by its tenant’s identity authority.
interface Card { recipientId: RecipientId; tenantId: TenantId; person: Person; issuedAt: Date; state: 'active' | 'superseded' | 'revoked'; replaces?: RecipientId;}struct Card { let recipientId: RecipientId let tenantId: TenantId let person: Person let issuedAt: Date let state: State let replaces: RecipientId?
enum State { case active, superseded, revoked }}data class Card( val recipientId: RecipientId, val tenantId: TenantId, val person: Person, val issuedAt: Instant, val state: State, val replaces: RecipientId?,) { enum class State { ACTIVE, SUPERSEDED, REVOKED }}state is the card’s status, as the withdrawal feed reports it:
active: the device can still open objects.superseded: the device enrolled a replacement. This card gave way to the newer one.replaceson the newer card names theRecipientIdit took over from.revoked: the card was withdrawn outright, after device revocation or a lost device.
A card that is no longer active locks the client that holds it. See The trust model for how that check runs.
Key domains, epochs, datasets and folders
A key domain is the unit of sharing. It has one key. Every device of every person and group who
may open the key domain has access to that key. Sharing, unsharing and making someone a domain
owner all act on a key domain’s root Locator through client.domains. Unsharing starts the key
domain’s next epoch, a fresh key generation. A person who leaves cannot open anything saved
after they left. The SDK does not change any object saved under an older epoch.
A dataset is a named collection. A person with the Owner or Admin role registers it once,
through client.datasets. Its root is itself a key domain. Registering a dataset creates the first
key for everything saved under it. A dataset also carries:
- its
indexFields - its optional
subjectField, for tokenizing a customer’s own identifier - its
segmentFields
Segment fields get their own key. The SDK can then withhold a masked field without hiding the whole record.
A folder is a location inside a dataset that client.folders.list opens as one decision. The
folder index itself is a stored object like any other, encrypted to the key domain it belongs to. A
folder can itself be a sub-domain, domainRoot on its Entry, when a tenant wants a subtree
shared differently from its parent.
Records hold structured fields. Files hold bytes and a media type. Both are objects. You
open, save and delete both the same way. Both carry a Locator, version and writer. They
differ only in the content you pass to save or create: RecordContent or FileContent.
Every save is a new version, never an edit in place. A VersionInfo records:
- who wrote the version
- the version it was based on
- whether it is
pending: an AI agent’s version its delegator has not accepted
Deleting an object or a key domain retires it into the recycle bin, domains.recycleBin. From
there, you can restore it or shred it for good.
Tenant └─ Dataset "encounters" (classification: phi, subject field: mrn) └─ Key domain (root Locator, current epoch) └─ Folder ├─ Record (Locator, version 3, fields) └─ File (Locator, version 1, bytes) Recycle bin: retired versions, objects and domains, until restored or shreddedNext
- Access decisions for how a call on any of these returns
Decided<T>. - The trust model for how the SDK verifies a
Cardand whattrust-failedmeans. - Share and Owners and sub-domains for
domainsin full. - Datasets for registering one.