Proje: OkulUp · Hub: OkulUp — Architecture

State Management

Teknoloji: Zustand v5

Pattern: create<Store>()(persist((set, get) => ({...}), { name, storage: AsyncStorage, partialize }))

Store’lar (src/store/slices/)

authSlice

state: { isAuthenticated, user, token, permissions, loginAt, loading, hasHydrated }
actions: setUser, setPermissions, setToken, setAuth, setLoading, logout, hydrate
persist: { user, token, permissions, isAuthenticated, loginAt }  // hasHydrated persist edilmez
  • onRehydrateStorage → token’ı Axios’a set eder, hasHydrated: true yapar
  • hydrate() → uygulama başlangıcında token’ı Axios’a restore eder

themeSlice

state: { mode: 'light'|'dark'|'system', isDark: boolean }
persist: { mode }  // isDark persist edilmez, runtime'da hesaplanır
  • setSystemDark(bool) → system modda isDark günceller
  • system mode: useColorScheme() hook’u takip eder

notificationSlice

Unread count’ları tutar: unreadTotal, unreadConversations, unreadAnnouncements WebSocket notification gelince incrementByType() ile artırılıyor

toastSlice

Global toast sistemi: showSuccess, showError, showWarning, showInfo ToastContainer root layout’ta render ediliyor

consentSlice

KVKK/gizlilik onay durumu persist ediyor

dashboardPrefsSlice

Dashboard tercih ayarları (hangi kartlar görünür vb.)

archivedChatsSlice

Arşivlenmiş konuşmalar listesi

Önemli Notlar

  • useAuthStore.getState() — hook dışında (servis katmanı) store erişimi için
  • Circular dependency: client.tsauthSlice → lazy require ile çözülmüş
  • permissions field: login’de getMe() ile backend’den çekiliyor + mobileConfig ile override

React Query ile İlişki

Zustand: global auth/theme/ui state React Query: server state (API data), cache, invalidation İkisi ayrı concern — karıştırılmıyor