Skip to Content
LearnArchitectureSystem Overview

System Overview

High-level architecture of Gluonic sync engine.

Three-Layer Architecture

Gluonic is organized into three distinct layers, each with clear responsibilities:

Layer 1: Data Store (Foundation)

Responsibilities:

  • Manage observable data pool
  • Coordinate server synchronization
  • Persist confirmed data locally
  • Queue and retry mutations
  • Handle network connectivity

Key Components:

  • Store - Central coordinator
  • ObjectPool - In-memory observable cache
  • StorageAdapter - Local database interface
  • MutationAdapter - Server API interface

Layer 2: Reactive Models (Abstraction)

Responsibilities:

  • Instantiate model instances from pool data
  • Provide identity mapping (same ID = same instance)
  • Enable lazy loading for relationships
  • Track optimistic updates
  • Implement field-level reactivity

Key Components:

  • Model - Base class for all models
  • IdentityMap - Identity map and cache
  • LazyReference - Lazy single relationship
  • LazyCollection - Lazy collection relationship
  • JavaScript Proxy - Transparent field access

Layer 3: React Integration (UI)

Responsibilities:

  • Integrate with React components
  • Provide hooks for data access
  • Trigger re-renders on data changes
  • Manage component lifecycle

Key Components:

  • useModel() - Get single model
  • useCollectionModels() - Get collection
  • GraphProvider - Context provider
  • observer() - MobX-React integration

Data Flow

Read Path (UI → Data)

Component calls useModel('post', '123') ↓ IdentityMap.getModel('post', '123') ↓ Check identity map cache ↓ If cached: return instance If not: instantiateModel(store, 'post', '123') ↓ Create Proxy wrapping Post instance ↓ Store in cache ↓ Return to component ↓ Component reads post.title (via Proxy GET) ↓ Proxy → store.pool.get('post', '123').p.title ↓ MobX tracks access ↓ Return value to component

Write Path (User Action → Server)

User action: store.save('post', '123', { title: 'New' }) ↓ 1. Apply optimistically to pool store.pool.upsert({ t: 'post', id: '123', p: { title: 'New' } }) ↓ 2. MobX triggers UI re-render Components update immediately ✓ ↓ 3. Queue mutation storage.enqueueTx(tx) ↓ 4. Send to server POST /sync/v1/tx ↓ 5. Server responds ├─ Success → persist + dequeue └─ Error → rollback + dequeue

Sync Path (Server → Client)

Server has new data ↓ WebSocket frame arrives OR delta sync pulls ↓ Store.applyFrames(frames) ↓ For each frame: ├─ Update pool ├─ Persist to storage └─ Invalidate cache ↓ MobX reacts to pool changes ↓ Components re-render with new data ✓

Synchronization Strategy

1. Bootstrap (Initial Load)

App starts ↓ lastSyncId = 0 ↓ Fetch all data from server ↓ Write to pool + storage ↓ Set lastSyncId

2. Delta Sync (Incremental)

Periodic or on reconnect ↓ Fetch changes since lastSyncId ↓ Apply to pool + storage ↓ Update lastSyncId

3. Queue Replay (Restore Optimistic State)

App restarts ↓ Bootstrap (load confirmed data) ↓ Replay queued transactions ↓ Apply optimistic updates to pool ↓ User sees pending edits ✓

4. Real-Time (WebSocket)

Connection established ↓ Server pushes SyncFrames ↓ Apply immediately ↓ UI updates in real-time ✓

Next Steps

Last updated on