Implementation Overview

← Documentation
STRVCT

Deep technical specifications for class lifecycle, slots, views, persistence, notifications, and build infrastructure.

Introduction

This document provides a detailed engineering specification of the Strvct framework implementation. It builds directly on the high-level concepts described in the Technical Overview and the architectural foundations in Naked Objects.

Strvct applications are composed of three primary layers: Model, UI, and Storage. The framework eliminates manual "glue" code by embedding structural metadata directly into model objects via Slots and Slot Annotations.

SvApp Top-level coordinator; holds model + userInterface SvWebUserInterface · SvCliUserInterface · SvHeadlessUserInterface UI Layer SvUserInterface Root SvNodeView Tree Lazy Miller views; Observes node slots; Responds to user events; No DOM leaks to model Model Layer SvModel : SvStorableNode Domain SvNode Graph Root of persistent state; Slots define properties; Subnodes define children; Runs headlessly in Node.js Storage Layer SvPersistentObjectPool IndexedDB & Cloud Monitors mutations; Batches dirty nodes; SHA-256 blob store; Garbage collects pools mutation notification getter, setter, & action calls mutation notification loads & stores Model is the authoritative source of truth. Views and Storage hold weak references to Model nodes; Model holds zero references to Views or Storage in return. Slot annotations carry enough information for UI generation, persistence, and synchronization to be handled automatically.

The Object & Class System

Strvct implements a structured class initialization pattern built on top of standard ES6 class syntax.

Class Lifecycle & Registration

Classes are defined inside an IIFE (Immediately Invoked Function Expression) and self-register using .initThisClass():

(class Character extends SvStorableNode {

    initPrototypeSlots () {
        // Declare instance slots (properties + metadata)
    }

    initPrototype () {
        // Configure class-wide prototype settings
    }

    init () {
        super.init();
        // Basic instance initialization
    }

    finalInit () {
        super.finalInit();
        // Relationship resolution & post-deserialization setup
    }

}.initThisClass());

Initialization Execution Sequence:

  1. initPrototypeSlots(): Invoked automatically during class registration. Defines slots and annotations on the class prototype. Must never call super.
  2. initPrototype(): Sets up prototype-wide default properties (e.g., this.setShouldStore(true)). Must never call super.
  3. init(): Called when an object is instantiated (new Class()). Performs basic property initialization. Always calls super.init().
  4. finalInit(): Called after an object is fully instantiated or deserialized from IndexedDB. Sets up complex object references and child subnodes. Always calls super.finalInit().

Slots & Slot Annotations

Slots are Strvct's property system. Instead of raw instance fields, properties are declared in initPrototypeSlots():

initPrototypeSlots () {
    {
        const slot = this.newSlot("name", "Default Name");
        slot.setSlotType("String");
        slot.setShouldStoreSlot(true);   // Persists to IndexedDB
        slot.setSyncsToView(true);       // Emits view update notifications
        slot.setCanEditInspection(true); // Editable in Property Inspector
    }
    {
        const slot = this.newSlot("inventory", null);
        slot.setFinalInitProto(InventoryNode); // Auto-creates default instance
        slot.setIsSubnodeField(true);         // Navigable tile in inspector
    }
}

Key Slot Annotations:

  • setSlotType(typeName): Declares expected type (String, Number, Boolean, Array, Object, ClassName). Enforces runtime type checks on setters.
  • setShouldStoreSlot(boolean): Controls whether the slot value is included in serialized JSON records.
  • setSyncsToView(boolean): Triggers change notifications to observing views upon mutation.
  • setCanEditInspection(boolean): Exposes property in the modifier-click (Option+Click) live Property Inspector.
  • setIsSubnode(boolean): Adds slot value directly to the parent's subnodes array.
  • setIsSubnodeField(boolean): Generates a navigable field tile in the inspector hierarchy.
  • setFinalInitProto(Class): Auto-instantiates default child objects during finalInit() if no record was loaded from storage.

Categories & Protocols

  • Categories (initThisCategory()): Extend existing classes across multiple files without modifying the base definition file (e.g., SvJsonGroup_patches.js adding applyJsonPatches() to SvJsonGroup).
  • Protocols (NameProtocol): Define required interface method stubs inheriting from Protocol to enable runtime interface compliance checks.

Model Layer Engineering

Node Hierarchy

The domain model is an object graph inheriting from SvNode. Every node contains:

  • subnodes: An ordered, unique collection of child SvNode objects.
  • parentNode: Reference to the parent SvNode.
  • title / subtitle: String properties displayed in summary tiles.
  • puuid: Persistent unique identifier string.

Subnode Patterns

  1. Stored Subnodes (setIsSubnode(true)): Permanent parent-child ownership relationships where child nodes are stored directly inside the parent's subnodes array and persisted together.
  2. Subnode Fields (setIsSubnodeField(true)): Properties where value state remains in a slot on the parent node, but a navigable field tile (SvField) is generated in the UI for inspecting child subnodes.

View Layer Architecture

Layered Class Hierarchy

The view system uses a deep, single-inheritance hierarchy where each layer adds a isolated capability:

SvElementDomView        (Wraps DOM element, enables alternative render backends)
 └─ SvCssDomView         (Manages inline CSS styles and class list)
     └─ SvSubviewsDomView  (Manages child view hierarchy)
         └─ SvListenerDomView (Event listener attachment)
             └─ SvVisibleDomView  (Viewport visibility tracking)
                 └─ SvGesturableDomView (Gesture recognizers: tap, pan, swipe, long-press)
                     └─ SvResponderDomView  (Focus management & keyboard navigation)
                         └─ SvControlDomView    (Target/Action pattern for control triggers)
                             └─ SvStyledDomView     (State-based style states: selected, active, disabled)
                                 └─ SvNodeView          (Binds model SvNode to DOM presentation)

The UI is rendered using nested Miller Column container views:

  1. SvStackView: Core navigation container. Contains a SvNavView (master column) and otherView (detail area). Automatically collapses on mobile viewports into a push/pop stack with breadcrumbs.
  2. SvBrowserView: Top-level application shell extending SvStackView with header breadcrumb navigation.
  3. SvNavView: Single navigation column containing header, scrollable SvTilesView, and footer.
  4. SvTilesView: Scrollable container for SvTile items. Handles keyboard cursor selection, drag-and-drop, and reordering gestures.
  5. SvTile: Visual presentation of a single model node or property slot.
SvBrowserView Breadcrumb Header: Workspace > Projects > Task SvNavView (Master Column) SvTilesView • SummaryTile: Project Alpha • SummaryTile: Project Beta [*] • SummaryTile: Project Gamma SvStackView (Detail Area) SvNavView (Detail Column) • PropertyTile: Name ("Project Beta") • PropertyTile: Status ("Active") • PropertyTile: Priority ("High")

Storage Layer Engineering

Persistent Object Pools (SvPersistentObjectPool)

Application data is stored locally in IndexedDB as object pools (one pool per document):

  • Row Key Format: poolId + puuid (Persistent UUID).
  • In-Pool References: { "*": puuid } (near references within the same document pool).
  • Cross-Pool References: { "**": poolId } (far references to external document roots, loaded asynchronously).

Transactional Persistence Lifecycle

  1. Mutation Tracking: Modifying a slot marked setShouldStoreSlot(true) invokes didMutate(), marking the node dirty.
  2. Event Loop Commit: At the end of the current browser event loop, all dirty nodes are bundled into a single atomic IndexedDB transaction.
  3. Deserialization Pipeline: On load, instanceFromRecordInStore() instantiates a blank object, invokes init(), populates slot state via loadFromRecord(), and executes finalInit() to reconnect object references.
  4. Garbage Collection: Traces the stored graph from the pool root. Unreachable records are automatically deleted.
  5. SHA-256 Blob Pool (SvBlobPool): Large binary assets (images, audio, files) are stored in a content-addressable store keyed by SHA-256 hash. Records store hash references rather than binary payloads.

Synchronization Infrastructure

Strvct provides loose coupling across layers using three notification utilities:

  1. SvNotificationCenter: Asynchronous notification dispatch. Nodes post named notifications; observing views register to handle them.
  2. SvSyncScheduler: Coalesces multiple notification method invocations in one event loop into a single UI sync pass.
  3. SvBroadcaster: Immediate, synchronous event broadcast for high-frequency internal events.
Model Node Slot Setter character.setName("Thorin") Slot setter updates value SvNotificationCenter postNotification("didChange") Dispatches to observers SvSyncScheduler & View scheduleTargetAndMethod() Coalesced view.syncFromNode()

Content-Addressable Build System (CAM)

Strvct avoids standard ES module imports and Webpack/Vite bundlers, using a custom Content-Addressable Memory (CAM) build system:

  1. ImportsIndexer (Build Time): Recursively walks _imports.json files to discover source files and dependency order. Outputs:
    • _index.json: Metadata catalog mapping resource paths to SHA-256 content hashes.
    • _cam.json.zip: Zip-compressed content bundle keyed by SHA-256 hash.
  2. SvResourceManager & SvHashCache (Runtime):
    • Fetches _index.json on app boot.
    • Scans missing hashes against IndexedDB SvHashCache.
    • If missing ratio $> 30\%$, downloads _cam.json.zip in one HTTP request.
    • If missing ratio $\le 30\%$, fetches individual missing files on demand.
    • Evaluates source files in dependency order via eval() with embedded sourceURL comments for complete DevTools debugging support.