PROJECT CASE STUDY
VibeLine
A full-stack messaging application with direct and group chat, media sharing, and WebRTC calls — built around ordered message persistence, idempotent write APIs, and server-enforced conversation membership.

When live delivery is not enough
Live delivery is only one part of messaging. Requests can be retried after a timeout, concurrent sends need a consistent order, and membership can change while a message is being written. The system needs durable conversation state and explicit access rules rather than treating the live connection as the source of truth.
Ordering messages across retries and membership changes
Concurrent sends, retried requests, and membership changes can race. Without a shared correctness boundary, a conversation can receive duplicate messages, inconsistent ordering, or writes from users whose access has just been removed.
Message sends and membership mutations lock the conversation row within PostgreSQL transactions. Sequence allocation and uniqueness constraints establish message order and deduplicate repeated client request IDs, while active membership is checked inside the send transaction. Rejoined members receive a new history boundary through joinedSequence.
Durable writes, transient notifications
A TypeScript monorepo separates the Next.js interface from a Fastify API and shares runtime-validated Zod contracts. PostgreSQL and Drizzle own persistence; HTTP handles writes, SSE delivers live events, and PostgreSQL LISTEN/NOTIFY distributes notifications between API instances. Sequence-based history supports new-message catch-up, while WebRTC handles one-to-one audio and video calls.
Messaging, media, and calls in one application
The implementation brings together direct and group conversations, message reactions and read receipts, image/video and voice messaging, one-to-one audio/video calls, expiring stories, and optional browser push notifications and in-conversation AI assistance.
Recovering missed changes, not just new messages
A message sequence is an effective cursor for recovering newly created messages, but it cannot recover missed edits and deletions to older messages. The next iteration should add mutation-aware reconciliation and preserve client request IDs across user retries, then verify these paths with browser-level reconnect tests.