domain

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package domain is the TWINOS domain pack: the only fabriq package with TWINOS-specific knowledge. It seeds three entities that exercise every fabric capability — site (plain aggregate), asset (graph edges), tag (telemetry metadata whose readings bypass per-row events).

Index

Constants

View Source
const ReadingsSeries = "tag_readings"

ReadingsSeries is the Timescale hypertable telemetry readings land in. Readings are written through Timeseries().BulkWrite — the event-bypass path: no per-row outbox events; the worker publishes conflated deltas.

Variables

This section is empty.

Functions

func RegisterAll

func RegisterAll(reg *registry.Registry) error

RegisterAll registers the TWINOS domain pack. Call it once at startup; follow with reg.Validate() (fabriq.New does both).

Types

type Asset

type Asset struct {
	grove.BaseModel `grove:"table:assets"`

	ID       string `grove:"id,pk" json:"id"`
	TenantID string `grove:"tenant_id,notnull" json:"tenant_id"`
	Version  int64  `grove:"version,notnull" json:"version"`
	Name     string `grove:"name,notnull" json:"name"`
	Kind     string `grove:"kind" json:"kind"` // pump, valve, motor, ...
	Serial   string `grove:"serial" json:"serial"`
	SiteID   string `grove:"site_id" json:"site_id"`
	ParentID string `grove:"parent_id" json:"parent_id"`
}

Asset is a piece of industrial equipment. It carries both graph edges: LOCATED_AT -> Site and CHILD_OF -> Asset (equipment hierarchy).

type BlobObject

type BlobObject struct {
	grove.BaseModel `grove:"table:blob_objects"`

	ID          string `grove:"id,pk"             json:"id"`
	TenantID    string `grove:"tenant_id,notnull" json:"tenantId"`
	ScopeID     string `grove:"scope_id"          json:"scopeId"`
	Version     int64  `grove:"version,notnull"   json:"version"`
	Hash        string `grove:"hash,notnull"      json:"hash"`
	Size        int64  `grove:"size,notnull"      json:"size"`
	ContentType string `grove:"content_type"      json:"contentType"`
}

BlobObject is the catalog row for a stored blob. Many BlobObjects may share a Hash (content dedup); the bytes live in the object store, the ref-count in blob_cas.

type BlobSource

type BlobSource struct {
	grove.BaseModel `grove:"table:blob_sources"`

	ID          string            `grove:"id,pk"             json:"id"`
	TenantID    string            `grove:"tenant_id,notnull" json:"tenantId"`
	ScopeID     string            `grove:"scope_id"          json:"scopeId"`
	Version     int64             `grove:"version,notnull"   json:"version"`
	ProjectID   string            `grove:"project_id"        json:"projectId"`
	Name        string            `grove:"name,notnull"      json:"name"`
	Provider    string            `grove:"provider"          json:"provider"`
	Endpoint    string            `grove:"endpoint"          json:"endpoint"`
	BasePath    string            `grove:"base_path"         json:"basePath"`
	AuthEnc     []byte            `grove:"auth_enc"          json:"-"`
	WatchConfig map[string]any    `grove:"watch_config"      json:"watchConfig"`
	FileFilter  map[string]any    `grove:"file_filter"       json:"fileFilter"`
	Tags        map[string]string `grove:"tags"              json:"tags"`
	Enabled     bool              `grove:"enabled"           json:"enabled"`
}

BlobSource is a connection record for an external storage provider. The auth credentials are stored ONLY as ciphertext (auth_enc); the plaintext map never touches a column.

type DigestNode

type DigestNode struct {
	grove.BaseModel `grove:"table:digest_nodes"`

	ID         string `grove:"id,pk"             json:"id"`
	TenantID   string `grove:"tenant_id,notnull" json:"tenantId"`
	Version    int64  `grove:"version,notnull"   json:"version"`
	Level      int    `grove:"level,notnull"     json:"level"`
	Kind       string `grove:"kind,notnull"      json:"kind"`
	ScopeName  string `grove:"scope_name"        json:"scopeName"`
	ScopeID    string `grove:"scope_id"          json:"scopeId"`
	SourceID   string `grove:"source_id"         json:"sourceId"`
	SourceKind string `grove:"source_kind"       json:"sourceKind"`

	SummaryHash string `grove:"summary_hash" json:"summaryHash"`
	ContentHash string `grove:"content_hash" json:"contentHash"`
	SemHash     string `grove:"sem_hash"     json:"semHash"` // 16-hex

	ChildIDs  []string `grove:"child_ids"  json:"childIds"`  // JSONB
	ParentIDs []string `grove:"parent_ids" json:"parentIds"` // JSONB
	UpdatedAt int64    `grove:"updated_at" json:"updatedAt"` // unix nanos
}

DigestNode is one node of a tenant's context-distillation Merkle tree. Levels: 0 = entity (per source row), 1 = scope/cluster backbone, 2 = tenant root. The summary text is content-addressed in the file-plane CAS (SummaryHash); ContentHash is the Merkle freshness key; SemHash is the SimHash fingerprint (16-hex). The vector lives in the vector plane (entity "digest_node"), not here.

type FsBookmark

type FsBookmark struct {
	grove.BaseModel `grove:"table:fs_bookmarks"`

	ID        string    `grove:"id,pk"             json:"id"`
	TenantID  string    `grove:"tenant_id,notnull" json:"tenantId"`
	ScopeID   string    `grove:"scope_id"          json:"scopeId"`
	Version   int64     `grove:"version,notnull"   json:"version"`
	UserID    string    `grove:"user_id,notnull"   json:"userId"`
	NodeID    string    `grove:"node_id,notnull"   json:"nodeId"`
	SortOrder int       `grove:"sort_order"        json:"sortOrder"`
	CreatedAt time.Time `grove:"created_at"        json:"createdAt"`
}

FsBookmark is a user's bookmark of an fs_node (a favourite), with a per-user sort order. Unique per (tenant, user, node).

type FsNode

type FsNode struct {
	grove.BaseModel `grove:"table:fs_nodes"`

	ID          string         `grove:"id,pk"             json:"id"`
	TenantID    string         `grove:"tenant_id,notnull" json:"tenantId"`
	ScopeID     string         `grove:"scope_id"          json:"scopeId"`
	Version     int64          `grove:"version,notnull"   json:"version"`
	ParentID    string         `grove:"parent_id"         json:"parentId"` // ""=root
	Name        string         `grove:"name,notnull"      json:"name"`
	Path        string         `grove:"path"              json:"path"`
	NodeType    string         `grove:"node_type,notnull" json:"nodeType"` // "folder" | "file"
	BlobID      string         `grove:"blob_id"           json:"blobId"`
	Size        int64          `grove:"size"              json:"size"`
	ContentType string         `grove:"content_type"      json:"contentType"`
	Checksum    string         `grove:"checksum"          json:"checksum"`
	IsLocked    bool           `grove:"is_locked"         json:"isLocked"`
	LockedBy    string         `grove:"locked_by"         json:"lockedBy"`
	Metadata    map[string]any `grove:"metadata"          json:"metadata"`
	MountConfig map[string]any `grove:"mount_config"      json:"mountConfig"`
	DeletedAt   *time.Time     `grove:"deleted_at"        json:"deletedAt"`
	DeletedBy   string         `grove:"deleted_by"        json:"deletedBy"`
	CreatedAt   time.Time      `grove:"created_at"        json:"createdAt"`
	UpdatedAt   time.Time      `grove:"updated_at"        json:"updatedAt"`
}

FsNode is a filesystem catalog node (folder or file) in the tree over the blob plane. parent_id is the adjacency truth; path is a materialized index maintained transactionally on move/rename. File nodes reference a blob_object (blob_id) with denormalized facets.

Metadata and MountConfig are JSONB NOT NULL columns. Nil maps must be normalised before any INSERT or UPDATE to avoid a NOT NULL constraint violation. The hooks below fire because the command plane reaches Postgres through pgdriver.PgTx.NewInsert / NewUpdate — grove's model-mutation API — which calls hook.RunModelBeforeInsert / RunModelBeforeUpdate on the model prior to executing the statement (adapters/postgres/tx.go ApplyChange).

func (*FsNode) BeforeInsert

func (n *FsNode) BeforeInsert(_ context.Context, _ *hook.QueryContext) error

BeforeInsert implements grove/hook.BeforeInsertHook. It fires via pgdriver.PgTx.NewInsert (called by adapters/postgres/tx.go ApplyChange) before the INSERT executes, normalising nil JSONB maps so the mount_config/metadata NOT NULL constraint is never violated.

func (*FsNode) BeforeUpdate

func (n *FsNode) BeforeUpdate(_ context.Context, _ *hook.QueryContext) error

BeforeUpdate implements grove/hook.BeforeUpdateHook for the same reason: pgdriver.PgTx.NewUpdate (also in ApplyChange) fires this before the UPDATE.

type FsPermission

type FsPermission struct {
	grove.BaseModel `grove:"table:fs_permissions"`

	ID            string    `grove:"id,pk"             json:"id"`
	TenantID      string    `grove:"tenant_id,notnull" json:"tenantId"`
	ScopeID       string    `grove:"scope_id"          json:"scopeId"`
	Version       int64     `grove:"version,notnull"   json:"version"`
	NodeID        string    `grove:"node_id,notnull"   json:"nodeId"`
	PrincipalType string    `grove:"principal_type"    json:"principalType"` // user|role|team
	PrincipalID   string    `grove:"principal_id"      json:"principalId"`
	Permission    string    `grove:"permission"        json:"permission"` // read|write|delete|admin
	GrantedBy     string    `grove:"granted_by"        json:"grantedBy"`
	CreatedAt     time.Time `grove:"created_at"        json:"createdAt"`
}

FsPermission is an ACL grant on an fs_node. Append-only: grant = insert, revoke = delete. Enforcement (effective-permission evaluation) lives in the consuming seam, not in fabriq.

type FsShare

type FsShare struct {
	grove.BaseModel `grove:"table:fs_shares"`

	ID            string     `grove:"id,pk"             json:"id"`
	TenantID      string     `grove:"tenant_id,notnull" json:"tenantId"`
	ScopeID       string     `grove:"scope_id"          json:"scopeId"`
	Version       int64      `grove:"version,notnull"   json:"version"`
	NodeID        string     `grove:"node_id,notnull"   json:"nodeId"`
	Token         string     `grove:"token,notnull"     json:"token"`
	Permission    string     `grove:"permission"        json:"permission"`
	ExpiresAt     *time.Time `grove:"expires_at"        json:"expiresAt"`
	MaxDownloads  *int       `grove:"max_downloads"     json:"maxDownloads"`
	DownloadCount int        `grove:"download_count"    json:"downloadCount"`
	PasswordHash  string     `grove:"password_hash"     json:"-"`
	CreatedBy     string     `grove:"created_by"        json:"createdBy"`
	CreatedAt     time.Time  `grove:"created_at"        json:"createdAt"`
}

FsShare is a share-link record for an fs_node. fabriq stores it verbatim; the seam generates the token, hashes the password, and enforces expiry/cap/password.

type Link struct {
	grove.BaseModel `grove:"table:links"`

	ID       string `grove:"id,pk" json:"id"`
	TenantID string `grove:"tenant_id,notnull" json:"tenant_id"`
	Version  int64  `grove:"version,notnull" json:"version"`
	Kind     string `grove:"kind,notnull" json:"kind"` // relationship type
	SourceID string `grove:"source_id,notnull" json:"source_id"`
	TargetID string `grove:"target_id,notnull" json:"target_id"`
	Note     string `grove:"note" json:"note"`
}

Link is a generic reified relationship between two assets, used to exercise fabriq's reified-edge projection with the demo domain's own vocabulary.

type Page

type Page struct {
	grove.BaseModel `grove:"table:pages"`

	ID       string `grove:"id,pk" json:"id"`
	TenantID string `grove:"tenant_id,notnull" json:"tenant_id"`
	Version  int64  `grove:"version,notnull" json:"version"`
	Title    string `grove:"title" json:"title"`
	Body     string `grove:"body" json:"body"`
}

Page is the KindDocument demo entity: a collaborative page-builder document. Its row is written ONLY by document-plane materialization (the command plane rejects document kinds); after the quiet window the merged CRDT state lands here with version++ and one ordinary page.updated event, so projections, search and audit see pages as normal entities.

type Site

type Site struct {
	grove.BaseModel `grove:"table:sites"`

	ID       string `grove:"id,pk" json:"id"`
	TenantID string `grove:"tenant_id,notnull" json:"tenant_id"`
	Version  int64  `grove:"version,notnull" json:"version"`
	Name     string `grove:"name,notnull" json:"name"`
	Code     string `grove:"code" json:"code"`
	Region   string `grove:"region" json:"region"`
}

Site is a physical location (plant, facility) assets live at.

type Tag

type Tag struct {
	grove.BaseModel `grove:"table:tags"`

	ID       string `grove:"id,pk" json:"id"`
	TenantID string `grove:"tenant_id,notnull" json:"tenant_id"`
	Version  int64  `grove:"version,notnull" json:"version"`
	Name     string `grove:"name,notnull" json:"name"`
	Unit     string `grove:"unit" json:"unit"`         // °C, bar, rpm
	Datatype string `grove:"datatype" json:"datatype"` // float, bool, int
	AssetID  string `grove:"asset_id" json:"asset_id"`
}

Tag is telemetry metadata: one measured point on an asset. The tag row itself is an ordinary aggregate (created/updated/deleted events); its readings are not.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL