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

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:
User requests reset โ Secure token generated
Token stored with expiration โ 24-hour validity
User clicks reset link โ Token validated
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.
๐ Project Links
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
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.