@@ -62,12 +62,61 @@ Central type definitions for Task, User, navigation params, and state shapes. En
6262### Q9. Why separate services into database/, firebase/, sync/, and notifications/?
6363
6464** 💡 Answer:**
65+
66+ ``` typescript
67+ // src/services/database/realmService.ts
68+ class RealmService {
69+ private realm: Realm | null = null ;
70+ async getAllTasks(userId : string ): Promise <Task []> { /* ... */ }
71+ }
72+
73+ // src/services/firebase/firebaseService.ts
74+ class FirebaseService {
75+ async signIn(email : string , password : string ) { /* ... */ }
76+ }
77+
78+ // src/services/sync/syncService.ts
79+ class SyncService {
80+ async syncLocalToRemote() { /* ... */ }
81+ }
82+
83+ // src/services/notifications/notificationService.ts
84+ class NotificationService {
85+ async scheduleTaskReminder(taskId : string , title : string , timestamp : number ) { /* ... */ }
86+ }
87+ ```
88+
89+ ** 🔍 Explanation:**
90+ Makes code easier to test, debug, and modify. Changes to Firebase don't affect Realm logic.
6591Each service has distinct responsibility: database (local storage), firebase (remote), sync (coordination), notifications (push). Follows single responsibility principle.
6692
6793<a name =" q10 " ></a >
6894### Q10. Explain the custom hooks pattern (useSyncStatus, useNetworkStatus).
6995
7096** 💡 Answer:**
97+
98+ ``` typescript
99+ // src/hooks/useSyncStatus.ts
100+ export const useSyncStatus = () => {
101+ const { status, lastSyncedAt, error } = useSelector (
102+ (state : RootState ) => state .sync
103+ );
104+ return {
105+ isSyncing: status === ' syncing' ,
106+ isSynced: status === ' succeeded' ,
107+ isError: status === ' failed' ,
108+ };
109+ };
110+
111+ // Usage in component
112+ const { isSyncing, isSynced } = useSyncStatus ();
113+ if (isSyncing ) {
114+ return <ActivityIndicator />;
115+ }
116+ ```
117+
118+ ** 🔍 Explanation:**
119+ Reusable, testable, and hides complexity. Multiple components can use same logic.
71120Encapsulates Redux selectors and derived state logic. Components get clean API without knowing Redux internals.
72121
73122
@@ -79,60 +128,264 @@ Encapsulates Redux selectors and derived state logic. Components get clean API w
79128### Q11. How does the offline-first architecture work?
80129
81130** 💡 Answer:**
131+
132+ ``` typescript
133+ // Create task - writes to Realm immediately
134+ const task = await realmService .createTask ({
135+ userId: user .uid ,
136+ title: ' Buy groceries' ,
137+ completed: false
138+ });
139+
140+ // Sync to Firebase when online
141+ if (isConnected ) {
142+ await syncService .syncLocalToRemote ();
143+ }
144+
145+ // Always read from Realm (works offline)
146+ const tasks = await realmService .getAllTasks (user .uid );
147+ ```
148+
149+ ** 🔍 Explanation:**
150+ Users can work offline. Changes queue locally and sync when connection returns.
82151All CRUD operations write to Realm first (local), then sync to Firestore when online. App always reads from Realm.
83152
84153<a name =" q12 " ></a >
85154### Q12. Explain the bidirectional sync strategy.
86155
87156** 💡 Answer:**
157+
158+ ``` typescript
159+ // Local to remote (syncService.ts)
160+ const unsyncedTasks = await realmService .getUnsyncedTasks (userId );
161+ for (const task of unsyncedTasks ) {
162+ await firebaseService .syncTaskToFirestore (task );
163+ await realmService .markTaskAsSynced (task .id );
164+ }
165+
166+ // Remote to local (syncService.ts)
167+ firebaseService .listenToTasks (
168+ tasks => {
169+ tasks .forEach (task => realmService .saveRemoteTask (task ));
170+ },
171+ error => console .error (' Sync error:' , error )
172+ );
173+ ```
174+
175+ ** 🔍 Explanation:**
176+ Ensures consistency across devices. Changes from any device propagate to all others.
88177Local-to-remote syncs unsynced tasks to Firestore. Remote-to-local listens to Firestore changes and updates Realm.
89178
90179<a name =" q13 " ></a >
91180### Q13. How are sync conflicts handled?
92181
93182** 💡 Answer:**
183+
184+ ``` typescript
185+ // realmService.ts - saveRemoteTask
186+ async saveRemoteTask (task : Task ): Promise < void > {
187+ const existingTask = this .realm .objects (' Task' )
188+ .filtered(' id == $0' , task.id)[0 ];
189+
190+ this.realm.write(() => {
191+ if (existingTask) {
192+ // Remote overwrites local
193+ existingTask.title = task.title;
194+ existingTask.updatedAt = task.updatedAt;
195+ existingTask.synced = true;
196+ } else {
197+ this.realm.create('Task', { ...task, synced: true });
198+ }
199+ });
200+ }
201+ ```
202+
203+ ** 🔍 Explanation:**
204+ Simple but can lose data. Trade-off for implementation simplicity. Could enhance with CRDTs.
94205Last-write-wins based on ` updatedAt ` timestamp. Remote changes always overwrite local if remote is newer.
95206
96207<a name =" q14 " ></a >
97208### Q14. Why mark tasks as ` synced: false ` on local changes?
98209
99210** 💡 Answer:**
211+
212+ ``` typescript
213+ // realmService.ts - updateTask
214+ async updateTask (id : string , userId : string , updates : Partial < Task > ) {
215+ this .realm .write (() => {
216+ Object .assign (task , {
217+ ... updates ,
218+ updatedAt: Date .now (),
219+ synced: false // Mark for sync
220+ });
221+ });
222+ }
223+
224+ // syncService.ts - syncLocalToRemote
225+ const unsyncedTasks = await realmService .getUnsyncedTasks (user .uid );
226+ for (const task of unsyncedTasks ) {
227+ await firebaseService .syncTaskToFirestore (task );
228+ }
229+ ```
230+
231+ ** 🔍 Explanation:**
232+ Efficient sync - only uploads changed tasks, not entire database.
100233Tracks which tasks need uploading to Firestore. Sync service queries unsynced tasks to upload.
101234
102235<a name =" q15 " ></a >
103236### Q15. Explain soft delete vs hard delete implementation.
104237
105238** 💡 Answer:**
239+
240+ ``` typescript
241+ // Soft delete - syncs to Firebase
242+ async deleteTask (id : string , userId : string ) {
243+ this .realm .write (() => {
244+ task .isDeleted = true ;
245+ task .synced = false ; // Will sync deletion
246+ task .updatedAt = Date .now ();
247+ });
248+ }
249+
250+ // Hard delete - after sync completes
251+ async permanentlyDeleteTask (id : string , userId : string ) {
252+ this .realm .write (() => {
253+ this .realm .delete (task );
254+ });
255+ }
256+ ```
257+
258+ ** 🔍 Explanation:**
259+ Soft delete ensures deletions sync to Firestore before permanent removal.
106260Soft delete marks ` isDeleted: true ` , hard delete removes from database. Soft delete allows sync of deletions.
107261
108262<a name =" q16 " ></a >
109263### Q16. How does the filter state work in TaskListScreen?
110264
111265** 💡 Answer:**
266+
267+ ``` typescript
268+ // TaskListScreen.tsx
269+ const { tasks, filter } = useAppSelector (state => state .tasks );
270+
271+ const filteredTasks = useMemo (() => {
272+ return tasks .filter (task => {
273+ if (filter === ' active' ) return ! task .completed ;
274+ if (filter === ' completed' ) return task .completed ;
275+ return true ;
276+ });
277+ }, [tasks , filter ]);
278+ ```
279+
280+ ** 🔍 Explanation:**
281+ Memoization prevents re-filtering on every render. Only recalculates when tasks or filter change.
112282Redux stores filter ('all'|'active'|'completed'), useMemo filters tasks client-side for performance.
113283
114284<a name =" q17 " ></a >
115285### Q17. Why use Redux Toolkit instead of plain Redux?
116286
117287** 💡 Answer:**
288+
289+ ``` typescript
290+ // tasksSlice.ts
291+ const tasksSlice = createSlice ({
292+ name: ' tasks' ,
293+ initialState ,
294+ reducers: {
295+ setTasks : (state , action ) => {
296+ state .tasks = action .payload ; // Immer makes this safe
297+ },
298+ toggleTaskComplete : (state , action ) => {
299+ const task = state .tasks .find (t => t .id === action .payload );
300+ if (task ) {
301+ task .completed = ! task .completed ; // Direct mutation works!
302+ }
303+ }
304+ }
305+ });
306+ ```
307+
308+ ** 🔍 Explanation:**
309+ Less code, fewer bugs, better DX. Immer handles immutability automatically.
118310RTK provides ` createSlice ` (reduces boilerplate), Immer (immutable updates), and configured store with DevTools.
119311
120312<a name =" q18 " ></a >
121313### Q18. Explain the serializableCheck middleware configuration.
122314
123315** 💡 Answer:**
316+
317+ ``` typescript
318+ // store/index.ts
319+ export const store = configureStore ({
320+ reducer: { auth: authReducer , tasks: tasksReducer },
321+ middleware : getDefaultMiddleware =>
322+ getDefaultMiddleware ({
323+ serializableCheck: {
324+ ignoredPaths: [' auth.user' ],
325+ ignoredActions: [' auth/setUser' ],
326+ },
327+ }),
328+ });
329+ ```
330+
331+ ** 🔍 Explanation:**
332+ Prevents console warnings while storing Firebase User. Trade-off: can't time-travel debug user object.
124333Redux requires serializable state, but Firebase User objects aren't serializable. Config ignores specific paths.
125334
126335<a name =" q19 " ></a >
127336### Q19. How does Realm change listener trigger UI updates?
128337
129338** 💡 Answer:**
339+
340+ ``` typescript
341+ // syncService.ts - initialize
342+ this .unsubscribeRealm = await realmService .addChangeListener (() => {
343+ if (this .isConnected ) {
344+ this .syncLocalToRemote ();
345+ }
346+ });
347+
348+ // realmService.ts - addChangeListener
349+ async addChangeListener (callback : () => void ) {
350+ const tasks = this .realm .objects (' Task' );
351+ const listener = () => callback ();
352+ tasks .addListener (listener );
353+ return () => tasks .removeListener (listener );
354+ }
355+ ```
356+
357+ ** 🔍 Explanation:**
358+ Reactive data flow: Realm change → sync → Redux update → UI re-render.
130359Realm listener calls callback on data changes, which loads tasks from Realm and dispatches to Redux, triggering re-render.
131360
132361<a name =" q20 " ></a >
133362### Q20. Why separate network state into its own Redux slice?
134363
135364** 💡 Answer:**
365+
366+ ``` typescript
367+ // networkSlice.ts
368+ interface NetworkState {
369+ isConnected: boolean ;
370+ type: string | null ;
371+ isInternetReachable: boolean | null ;
372+ }
373+
374+ // NetworkProvider.tsx
375+ NetInfo .addEventListener (state => {
376+ dispatch (setNetworkState ({
377+ isConnected: state .isConnected ?? false ,
378+ type: state .type ,
379+ isInternetReachable: state .isInternetReachable ?? null
380+ }));
381+ });
382+
383+ // Usage in components
384+ const { isConnected } = useAppSelector (state => state .network );
385+ ```
386+
387+ ** 🔍 Explanation:**
388+ Single source of truth. Components react to network changes without managing listeners.
136389Network status affects multiple features (sync, offline banner). Centralized state prevents duplicate listeners.
137390
138391
0 commit comments