Social Media App
Build a real-time social app: posts, likes, comments, 1:1 chat, and push notifications. This project owns the real-time + offline-first skill set — outbox, WebSocket, Firestore listeners, and FCM.
The user journey
Sign in (Google/Phone) → Feed → Post detail (comments)
│
├─ New post (camera, upload)
├─ Inbox → Conversation (real-time messaging)
└─ Profile (own & others)
Features (by milestone)
M1 — Auth + skeleton
- Firebase Auth: Google Sign-In + Phone OTP
:feature:authwith sealed auth states (SignedOut, OtpSent, Verifying, SignedIn)- Bottom nav: Feed, Search, New Post, Inbox, Profile
- Network Security Config with cert pinning
M2 — Feed + posts
- Firestore-backed feed with
snapshots().addSnapshotListener() - Room caches posts for offline viewing
- Post creation: capture/pick image → Cloud Storage upload → Firestore doc
- Likes, comments (sub-collection), share intents
- Paging 3 integration with Firestore cursor pagination
M3 — Real-time messaging (offline-first)
User types → Room INSERT (status=SENDING, client-id=UUID)
↓ enqueue
OutboxWorker → WebSocket.send() → ack → Room UPDATE (status=SENT)
↑ on failure
└── 4xx: FAILED | 5xx/timeout: retry with backoff
- WebSocket-based chat (OkHttp) with reconnection + resume cursor
- Outbox worker using WorkManager
- Typing indicator (debounced Flow), read receipts
- Message search across all conversations (Room FTS5)
M4 — Push + media
- FCM with topic + direct-user notifications
- Notification channels per category (messages, mentions, updates)
- Deep links from notifications into specific conversations/posts
- Image/video compression on upload (WorkManager job)
- Video thumbnail generation; cached with Coil
M5 — Production hardening
- Play Integrity on post creation (anti-spam)
- Content moderation: ML Kit on-device image classification
- Accessibility: TalkBack-complete conversations, custom actions for archive/delete
- i18n: plurals, date formatting, RTL
- Baseline profile for feed + chat
M6 — Ship
- CI with sharded unit tests + instrumented tests on emulator matrix
- Fastlane internal + closed beta + production
- Data Safety declaration matching all Firebase SDKs
- Privacy policy + CMP integration
- Crash + ANR SLOs + automatic rollout halt (Module 17)
Architecture highlights
Offline-first messaging repository
class MessageRepository @Inject constructor(
private val dao: MessageDao,
private val outbox: OutboxDao,
private val socket: ChatSocket,
private val workManager: WorkManager
) {
fun observe(conversationId: String): Flow<List<Message>> =
dao.observe(conversationId).map { it.map(MessageEntity::toDomain) }
suspend fun send(conversationId: String, body: String): Message {
val local = MessageEntity(
id = Uuid.random().toString(),
conversationId = conversationId,
authorId = currentUserId(),
body = body,
sentAt = now(),
status = MessageStatus.SENDING
)
dao.insert(local)
outbox.enqueue(OutboxItem.SendMessage(local.id))
workManager.enqueueUniqueWork(
"outbox",
ExistingWorkPolicy.KEEP,
OneTimeWorkRequestBuilder<OutboxWorker>()
.setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
.build()
)
return local.toDomain()
}
}
WebSocket lifecycle-aware
class ChatSessionManager @Inject constructor(
private val socket: ChatSocket,
private val processLifecycle: ProcessLifecycleOwner
) {
fun start(token: String, conversationId: String) {
processLifecycle.lifecycle.coroutineScope.launch {
processLifecycle.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
socket.connect(token, conversationId)
try { awaitCancellation() } finally { socket.close() }
}
}
}
}
Stretch goals
🎙️
Voice messages
Record audio, compress (Opus), upload to Cloud Storage, playback inline with waveform.
🖼️
Stories
24-hour ephemeral posts with Compose animation. Background WorkManager cleanup.
🔔
Rich notifications
Direct reply from the notification shade (RemoteInput + Direct Reply).
🎨
AR filters
ML Kit face detection + Compose overlay. Real-time at 30fps.
🌐
Web viewer
Compose Multiplatform share target — same code renders posts in web version.
Testing strategy
- Firestore emulator in CI for integration tests
- MockWebServer simulates WebSocket for unit tests
- Robolectric for WorkManager outbox tests
- Compose tests for conversation UI (typing, read receipts, scroll-to-bottom)
- Macrobenchmark for feed scroll frame timing
Privacy considerations (you own this)
- E2E encryption opt-in for chats (Signal Protocol via libsignal)
- Local-only data for drafts — never sync to backend
- Explicit opt-in for each analytics SDK
- Delete-account flow that cascades (Firestore function + Cloud Storage purge)
Next
Continue to Project 3 — Food Delivery for Maps, live location, and foreground services.