Storage to GraphQL Backend
Converting Local Storage to a GraphQL Backend
Section titled “Converting Local Storage to a GraphQL Backend”Context: Domain data is persisted via a single abstraction in shaker/infra/localStorage.ts (MMKV). This document explains why moving to a GraphQL (or other) backend is straightforward and outlines possible strategies.
Why the conversion is straightforward
Section titled “Why the conversion is straightforward”Single abstraction
Section titled “Single abstraction”All domain reads and writes go through getItem and setItem and the fixed set of STORAGE_KEYS. No domain module in shaker/data/* knows whether the backend is local (MMKV) or remote (GraphQL). Swapping the implementation behind that interface is a controlled, infra-only change.
Existing “backend ready” hints
Section titled “Existing “backend ready” hints”The codebase already has TODOs and comments (e.g. in shaker/app/(tabs)/venues/[id].tsx, shaker/data/products/index.ts) such as “Replace with GraphQL mutation when backend is ready.” The data shape (products, venues, recipes, etc.) is already the natural mapping to GraphQL types and operations. The same TypeScript types used for hydration can be used for API responses.
Possible backend strategies
Section titled “Possible backend strategies”Strategy A – Adapter swap
Section titled “Strategy A – Adapter swap”Introduce a “persistence adapter” (e.g. LocalStorageAdapter vs GraphQLAdapter) that implements the same interface used by the app today:
getItem(key)– For each key, map to a GraphQL query (or REST endpoint) that returns the same payload type (e.g.ProductsStoragePayload,Venue[]).setItem(key, value)– Map to a GraphQL mutation (or REST) that updates the server; optionally invalidate caches or trigger refetch.
Hydration and all persist*() calls stay the same; only the implementation of the adapter changes (and possibly environment or config to choose which adapter is used).
Strategy B – Repository per domain
Section titled “Strategy B – Repository per domain”Replace direct getItem/setItem per key with a small repository per domain (e.g. ProductRepository, VenueRepository) that:
- Exposes the same logical operations the app already has (get list, add, update, delete).
- Today: Implementation uses MMKV (read/write the same JSON blobs).
- Later: Implementation uses GraphQL queries and mutations. The rest of the app depends on the repository interface, not on storage.
Strategy C – Hybrid (offline-first)
Section titled “Strategy C – Hybrid (offline-first)”Keep MMKV as a local cache. The repository (or adapter) reads from GraphQL when online and writes to MMKV; reads prefer MMKV for speed and offline use. Sync logic (e.g. queue mutations when offline) can be added later.
What to keep consistent for an easy conversion
Section titled “What to keep consistent for an easy conversion”- Key–domain mapping: Keep
STORAGE_KEYS(or an equivalent list) as the canonical set of “domain blobs.” GraphQL can mirror these as one query per key or one query per entity type. - Payload types: Keep the same TypeScript types (e.g.
ProductsStoragePayload,Venue[],Recipe[]) so that when the backend returns JSON from GraphQL, the same types and hydration logic apply. - No direct storage in features: Ensure no feature or data code imports MMKV or AsyncStorage directly; all persistence goes through
localStorage.ts(or the future adapter/repository). That way swapping to GraphQL only touches the infra layer.
High-level flow
Section titled “High-level flow”flowchart LR
subgraph today [Current]
UI[UI / Screens]
Data[Data modules]
Hydrate[hydrateLocalStorage]
Infra[localStorage.ts]
MMKV[MMKV]
UI --> Data
Hydrate --> Infra
Data --> Infra
Infra --> MMKV
end
subgraph future [With GraphQL]
UI2[UI / Screens]
Data2[Data modules]
Hydrate2[hydrateLocalStorage]
Adapter[Persistence adapter]
GQL[GraphQL API]
UI2 --> Data2
Hydrate2 --> Adapter
Data2 --> Adapter
Adapter --> GQL
end
Data modules and hydration stay the same; only the implementation behind localStorage or the adapter changes from MMKV to GraphQL.
References
Section titled “References”- Local storage options (MMKV) – Current persistence implementation.
shaker/infra/localStorage.ts– Single storage abstraction andSTORAGE_KEYS.