← funsho cornelius
case study 01 — real-time marketplace

Pikkam

A peer-to-peer marketplace with live buyer–seller chat — built to feel instant and never lose a message, on the real mobile networks Nigerians actually use.

role
Frontend Engineer — chat, listings, data layer
focus
Real-time chat · optimistic UI · cache reconciliation
data
RTK Query · Socket.IO · 18-entry invalidation graph
timeline
Aug 2025 – Apr 2026
pikkam.app/chat/thread
Pikkam buyer–seller chat thread, showing sent messages and reconciled history

Chat is where a marketplace deal happens — so it can't feel slow or drop a message.

Buyers and sellers negotiate in real time. If a message takes a beat to send, or silently vanishes on a dropped connection, trust goes with it. Listing something also had to be fast enough that a casual seller doesn't abandon halfway. All of this on mobile data that cuts out mid-request.

Three things working against a good experience.

—

Lossy networks are the norm, not the edge case. Requests time out, sockets drop and reconnect, uploads stall. The UI had to assume this constantly.

—

Two sources of truth for the same data. Messages arrive both from your own optimistic send and from the socket echo — the cache has to stay correct without duplicating or losing either.

—

One session, three consumers. Server components, RTK Query, and the socket handshake all needed to share the same auth without three separate login states.

One cache as the single source of truth — everything reconciles into it.

// real-time chat
Optimistic sends, socket-driven reconciliation

The RTK Query cache is the single source of truth. Messages send with a temp ID and roll back on failure; incoming socket events are de-duped against in-flight sends, so the thread never doubles up or loses a line.

// surgical refetching
An 18-entry tag invalidation graph

A deliberate map of which mutations invalidate which queries, so an action refetches exactly what changed — not the whole screen — keeping data requests light on slow connections.

// AI-assisted listing
Snap a photo, get a filled-in form

Image analysis pre-fills the listing form, with low-confidence guards that flag uncertain fields and a review-before-publish step — speed without letting the model publish something wrong.

// lossy-network hardening
Built to survive bad data

A 45-second upload timeout race, exponential-backoff retries, and plain-language error recovery so a dropped request becomes “tap to retry,” not a dead end.

// shared session
Dual-cookie auth across three consumers

A dual-cookie session shared by server components, RTK Query, and the socket handshake — one identity, no divergent login states between the three.

Every piece pointed at the same goal: a chat that behaves like the network is perfect, on a network that never is.

Keeping one cache correct when the same message arrives twice.

You send a message: it appears instantly with a temporary ID. A moment later the server broadcasts that same message back over the socket, now with a real ID. Naively, you'd render it twice. Handle it too aggressively and you drop the real one and keep a temp that never confirms.

The fix was to treat the cache as authoritative and reconcile every inbound event against it: match the socket echo to its in-flight temp send, swap the temp ID for the real one in place, and drop the event if it's already reconciled. Same logic covers the reconnect case — when the socket comes back and replays events, nothing duplicates. That single reconciliation rule is what makes the chat feel effortless.

// message reconciliation — temp id → socket echo0 dupes
Pikkam chat thread with sent messages

Chat that feels instant and holds up when the network doesn't.

Messages send optimistically and reconcile cleanly across reconnects; listings go up in a few taps with AI doing the tedious part; and the whole data layer stays light on slow connections. The reconciliation and hardening patterns became the template for the app's other real-time surfaces.

1 cache
source of truth for REST + socket data
18
tag entries for surgical refetches
0
duplicated or lost messages across reconnects
Next.js 16React 19RTK QuerySocket.IOCloudinaryZodTailwind v4TypeScript
next case study →
Blessing Computers
02 — systems & architecture ↗