Android Offline-First Grocery List App
Build an Android grocery list app in Kotlin that works fully offline and syncs with a server when the connection returns, so a family can share one list. Room is the source of truth: every change is saved locally at once and marked as pending, WorkManager sends pending changes to a REST API with Retrofit in the background and pulls changes made on other phones, and version numbers detect when the same item was edited on two phones, so the conflict can be resolved instead of one edit silently winning. You'll build the small sync server too. You'll learn offline-first architecture, Room, WorkManager with constraints and backoff, Retrofit, sync protocols with versions, conflict resolution, and testing offline and online transitions.
- Estimate
- ~12.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Jetpack Compose · Room · WorkManager · Retrofit
Project roadmap
- 01
Design the offline-first schema
~2hWrite SYNC.md and create a Room entity for grocery items: a UUID made on the phone, name, quantity, checked, category, updated at, the server version, a deleted flag (so deletions can sync) and a sync status (pending, synced or conflicted). Describe the API (push changed items with the version they were based on, and pull items changed since a cursor) and the conflict rules. Done when: SYNC.md is written, and the entity and DAO compile.
- 02
Build the screens
~2hBuild Compose screens that read from Room through a ViewModel: the list grouped by category with checkboxes, and a form to add and edit items. Every change is written to Room immediately with status pending; deleting sets the deleted flag and hides the item. Show a small marker on unsynced items. Done when: the app works completely in airplane mode.
- 03
Build the sync server
~2hWrite a small REST server (for example with Ktor) that stores items with a version number that increases on every change, accepts pushes only when the pushed version matches the stored one (otherwise returning a conflict with the current item), and returns changes since a cursor. Done when: the server's API works and reports conflicts.
- 04
Sync with WorkManager
~2.5hDefine the API with Retrofit and write a CoroutineWorker that pushes pending items, marks accepted ones synced with their new version, pulls remote changes since the saved cursor and applies them (unless the local copy has newer pending changes), and saves the new cursor. Schedule it as unique periodic work with a network constraint, and also after local changes, with exponential backoff on failure. Done when: changes made offline reach the server after reconnecting, and changes from another phone appear.
- 05
Resolve conflicts
~2hWhen the server reports a conflict, mark the item conflicted and store the server's version next to the local one. Merge automatically when the changes touch different fields (for example one phone checked the item and another changed the quantity), and otherwise show both versions to the user to choose. Done when: editing the same item on two offline phones ends with an automatic merge or a clear choice, never a silent loss.
- 06
Test offline and online transitions
~2hWrite tests: DAO tests, the worker against a fake server (success, conflicts, timeouts and server errors), the merge rules as pure functions, and a simulation of two devices making random offline changes and syncing until both match the server. Test by hand with two emulators, airplane mode and app restarts mid-sync. Done when: all tests pass, and the manual checks keep data consistent.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack