Day 4 of Demolishing my Stack of Unfinished Projects: Secret Chat

Christian TioyeChristian Tioye
7 min read

Published on Aug 21st, 2025

๐Ÿš€ Made some progress

Welcome back to my "Demolishing My Stack of Unfinished Projects" series! This week, I'm excited to share the story of how I transformed a simple chat idea into a fully-featured, production-ready real-time messaging application called CodeniChat (formerly Secret Chat Bolt).

๐ŸŽฏ The Project That Started It All

Secret Chat began as one of those "wouldn't it be cool if..." moments. I had this idea for a secure, real-time chat application that could handle multiple rooms, user invitations, and password resets. You know the drill - you start with enthusiasm, then life happens, and suddenly it's been months with just a README file and some half-baked code.

But this week, I decided enough was enough. It was time to demolish this unfinished project and turn it into something I could actually be proud of. I started off with a short prompt into the bolt.new platform


๐Ÿ› ๏ธ The Tech Stack That Made It Possible

Frontend

  • Next.js 15 - The latest and greatest React framework

  • React 19 - Cutting-edge React with the new compiler

  • TypeScript - Because type safety is not optional

  • Tailwind CSS - For rapid, beautiful UI development

  • shadcn/ui - Pre-built, accessible components

Backend & Database

  • Neon Database - Serverless PostgreSQL that scales with you

  • Drizzle ORM - Type-safe database operations

  • NextAuth.js - Secure authentication system

  • Bcryptjs - Password hashing and security

Real-time Features

  • Server-Sent Events - For real-time message updates

  • WebSocket-like functionality - Without the complexity


๐Ÿš€ The Week-Long Development Sprint

Day 1: Foundation & Database

I started by setting up the database schema with Drizzle ORM. The beauty of using a modern ORM is that you can define your relationships once and let TypeScript handle the rest.

// Core tables for the chat system
export const users = pgTable("users", {
  id: text("id").primaryKey(),
  email: text("email").notNull().unique(),
  name: text("name").notNull(),
  password: text("password").notNull(),
  createdAt: timestamp("created_at").defaultNow(),
});

export const rooms = pgTable("rooms", {
  id: text("id").primaryKey(),
  name: text("name").notNull(),
  isPrivate: boolean("is_private").default(false),
  createdBy: text("created_by").references(() => users.id),
  createdAt: timestamp("created_at").defaultNow(),
});

Day 2: Authentication & User Management

NextAuth.js made implementing authentication a breeze. I added signup, signin, and even a password reset flow that generates secure tokens and handles the entire reset process.

The Password Reset Flow:

  1. User requests reset โ†’ Secure token generated

  2. Token stored with expiration โ†’ 24-hour validity

  3. User clicks reset link โ†’ Token validated

  4. New password set โ†’ Token marked as used

Day 3: Real-Time Chat Core

This was the fun part! I implemented the core chat functionality with:

  • Message grouping - Consecutive messages from the same user are visually grouped

  • Auto-scroll - Intelligent scrolling that doesn't interfere with user reading

  • Room management - Public and private rooms with automatic user assignment

Day 4: The Invitation System

One of the most requested features in any chat app - the ability to invite users to rooms. I built:

  • Invite modal - Select users from a filtered list

  • Pending invitations - Sidebar display of received invites

  • Accept/Decline actions - One-click room joining

Day 5: UI/UX Polish & Branding

I transformed the generic "ChatApp" into CodeniChat with:

  • Custom favicon - SVG-based chat icon

  • Responsive design - Works on all devices

  • Modern UI components - Using shadcn/ui for consistency

  • Footer addition - Copyright and "made with love" message

Day 6: Next.js 15 Upgrade

This was a significant milestone. I upgraded from Next.js 13 to Next.js 15, which involved:

  • React 19 upgrade - Latest React features

  • TypeScript improvements - Stricter type checking

  • Build optimization - Better performance and smaller bundles

Day 7: Deployment & Final Touches

The final day was all about getting this baby deployed:

  • Vercel configuration - Optimized for Next.js 15

  • Environment setup - Secure configuration management

  • Final testing - Ensuring everything works in production


๐ŸŽจ Key Features That Make This App Special

1. Intelligent Message Grouping

const groupedMessages = useMemo(() => {
  return messages.reduce((groups: GroupedMessage[], message, index) => {
    const prevMessage = messages[index - 1];
    const nextMessage = messages[index + 1];

    const isFirstInGroup =
      !prevMessage ||
      prevMessage.user.id !== message.user.id ||
      message.createdAt.getTime() - prevMessage.createdAt.getTime() >
        5 * 60 * 1000;

    // Group logic implementation...
  }, []);
}, [messages]);

2. Smart Auto-Scroll

The app intelligently detects when users are reading older messages and won't force-scroll them to the bottom. But when they're at the bottom, new messages automatically appear.

3. Room Invitation System

Users can invite others to private rooms, and pending invitations are clearly displayed in the sidebar with accept/decline buttons.

4. Password Reset Flow

Complete password recovery system with secure token generation and validation.


๐Ÿšง Challenges I Faced (And How I Overcame Them)

1. Next.js 15 Compatibility Issues

Problem: The upgrade introduced breaking changes in API routes and required new Suspense boundaries.

Solution: I updated all API route parameters to use Promise<{ roomId: string }> and wrapped components using useSearchParams() in Suspense boundaries.

2. Vercel Deployment Issues

Problem: Next.js 15 peer dependency conflicts during deployment.

Solution: Used npm install --legacy-peer-deps in the build process and configured vercel.json accordingly.

3. Real-Time Message Updates

Problem: Implementing real-time features without WebSockets.

Solution: Used Server-Sent Events with a custom hook that handles reconnection and message buffering.


๐Ÿ“Š What I Learned

1. Modern React is Incredible

React 19 with the new compiler is a game-changer. The performance improvements and developer experience are noticeable from day one.

2. TypeScript + Drizzle = Database Bliss

Having type-safe database operations eliminates entire classes of bugs. I can't imagine building a production app without this combination.

3. Component Libraries Save Time

shadcn/ui provided beautiful, accessible components that I could customize while maintaining consistency. This saved me hours of CSS work.

4. Incremental Development Works

By building features one day at a time, I was able to test and refine each component before moving to the next. This prevented the "everything is broken" syndrome.


๐ŸŽฏ What's Next for CodeniChat?

While this project is now "complete" in terms of core functionality, I'm already thinking about future enhancements:

  • File sharing - Upload and share images, documents

  • Voice messages - Audio recording and playback

  • End-to-end encryption - For truly private conversations

  • Mobile app - React Native version

  • Push notifications - For important messages


๐Ÿ† The Result: A Project I'm Actually Proud Of

Secret Chat Bolt went from being another unfinished project in my stack to a fully-functional, production-ready chat application. Here's what I accomplished in just one week:

โœ… Complete authentication system
โœ… Real-time messaging
โœ… Room management
โœ… User invitations
โœ… Password reset flow
โœ… Modern, responsive UI
โœ… Next.js 15 + React 19
โœ… Production deployment


๐Ÿ’ก Key Takeaways for Fellow Developers

1. Start Small, Build Incrementally

Don't try to build everything at once. Pick one feature, implement it completely, then move to the next.

2. Use Modern Tools

Next.js 15, React 19, and Drizzle ORM made this project enjoyable instead of frustrating.

3. Focus on User Experience

Little details like message grouping and smart scrolling make a huge difference in how users perceive your app.

4. Deploy Early and Often

Getting your app running in production early helps identify issues you won't catch in development.


  • Live Demo: [Your deployed URL]

  • GitHub Repository: [Your repo URL]

  • Tech Stack: Next.js 15, React 19, TypeScript, Neon DB, Drizzle ORM


๐ŸŽ‰ Conclusion

Secret Chat Bolt is no longer part of my unfinished projects stack. It's a living, breathing application that people can actually use. The satisfaction of completing a project like this is incredible, and it's motivated me to tackle the next unfinished project in my stack.

Remember: Every finished project started as an unfinished one. The key is to break it down into manageable pieces and tackle them one day at a time.

What's the next unfinished project in your stack that you're going to demolish? Let me know in the comments below!


This post is part of my "Demolishing My Stack of Unfinished Projects" series, where I tackle one unfinished project per week and turn it into something I can be proud of. Follow along for more project completion stories, technical deep-dives, and lessons learned from the trenches of software development.


Tags: #NextJS #React #TypeScript #ChatApp #FullStack #WebDevelopment #ProjectCompletion #RealTimeChat #Database #Authentication

0
Subscribe to my newsletter

Read articles from Christian Tioye directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Christian Tioye
Christian Tioye

I am software engineer based in Louisville Metro. My goals for 2023 is to complete my Master degree in Computer Science and start a full-time role building software to power the modern world.