The real-time data synchronization layer for Pattern Stack. Sits between backend-patterns and frontend-patterns to enable local-first, offline-capable applications with Linear/Notion-level UI snappiness.
OPENAPI SPEC
(single source of truth)
│
▼
┌──────────────────────────────────────────────────────────────┐
│ SYNC-PATTERNS CLI │
│ (generates typed clients) │
└──────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
frontend-patterns swift-patterns kotlin-patterns
(React) (SwiftUI) (Android)
│ │ │
▼ ▼ ▼
useLiveQuery @Observable Flow<T>
useQuery async/await suspend fun
Traditional API-first architecture:
User clicks → API call → Wait 200-500ms → UI updates
Local-first architecture (Linear, Notion):
User clicks → UI updates instantly → Sync happens in background
Features declare their sync mode in the OpenAPI spec:
paths:
/contacts:
x-sync: live # real-time, local-first
/analytics:
x-sync: push # traditional API callsThe CLI generates appropriate code for each mode:
Live mode (local-first, instant):
export function useContacts() {
return useLiveQuery(db.contacts.liveMany())
}Push mode (traditional, API-backed):
export function useContacts() {
return useQuery({
queryKey: ['contacts'],
queryFn: () => api.get('/contacts')
})
}Components consume a unified interface - they don't know or care which mode is active:
function ContactList() {
const { data } = useContacts() // works either way
return data.map(c => <Contact key={c.id} {...c} />)
}┌─────────────────────────────────────────────────────────────┐
│ EXTERNAL WORLD │
│ HubSpot · Salesforce · Google │
└─────────────────────┬───────────────────────────────────────┘
│ webhooks / polling
▼
┌─────────────────────────────────────────────────────────────┐
│ BACKEND-PATTERNS │
│ Business logic · Normalization · Orchestration │
│ PostgreSQL │
└─────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ SYNC LAYER │
│ ElectricSQL / Zero / TanStack DB │
│ Real-time · Offline · Optimistic │
└─────────────────────┬───────────────────────────────────────┘
│ instant sync
▼
┌─────────────────────────────────────────────────────────────┐
│ FRONTEND-PATTERNS │
│ Local DB (SQLite) · Instant reads · Instant writes │
└─────────────────────────────────────────────────────────────┘
- OpenAPI as source of truth - Types and sync modes declared once, generated everywhere
- Progressive enhancement - Start with
push, flip tolivewhen ready - Backend unchanged - Pattern Stack handles business logic, sync-patterns handles delivery
- Cross-platform - Same spec generates React, SwiftUI, Kotlin clients
- Unified interface - Components are agnostic to sync mode
| Engine | Pros | Cons |
|---|---|---|
| ElectricSQL | Works with existing Postgres, mature | Requires specific Postgres setup |
| Zero | Clean API, good DX | Newer, smaller ecosystem |
| TanStack DB | Incremental adoption, TanStack ecosystem | Very new (2024) |
| Convex | Turnkey, great DX | Opinionated backend (may conflict with Pattern Stack) |
Phase: Planning
This repo captures the architectural vision. Implementation will follow once backend-patterns and frontend-patterns reach stability.
- backend-patterns - Atomic Architecture backend framework
- frontend-patterns - React frontend framework
- Linear sync engine talks - Tuomas Artman
- Zero - Aaron Boodman's sync engine
- ElectricSQL - Postgres to SQLite sync