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 coordinatorObjectPool- In-memory observable cacheStorageAdapter- Local database interfaceMutationAdapter- 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 modelsIdentityMap- Identity map and cacheLazyReference- Lazy single relationshipLazyCollection- 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 modeluseCollectionModels()- Get collectionGraphProvider- Context providerobserver()- 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 componentWrite 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 + dequeueSync 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 lastSyncId2. Delta Sync (Incremental)
Periodic or on reconnect
↓
Fetch changes since lastSyncId
↓
Apply to pool + storage
↓
Update lastSyncId3. 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
- Data Pipeline - Detailed flow
- Sync Protocol - Wire format
- How Reactivity Works - MobX deep dive
Last updated on