A real-time, private bookmark manager built with Next.js, TypeScript, Tailwind CSS, and Supabase.
- Google OAuth: Fast and secure sign-in via Supabase Auth.
- Real-time Updates: Instant UI sync across devices using Supabase Realtime.
- Private Bookmarks: Row Level Security (RLS) ensures only you see your bookmarks.
- Sleek UI: Modern, responsive design with "Glassmorphism" aesthetics using Tailwind CSS and Framer Motion.
- CRUD Operations: Add, view, and delete bookmarks seamlessly.
SmartBookMark/
├── src/
│ ├── app/ # Next.js App Router (Pages & API)
│ │ ├── auth/ # OAuth Callback handlers
│ │ └── globals.css # Premium Design Tokens
│ ├── components/ # Premium Glassmorphism UI Components
│ ├── utils/ # Supabase Client & Middleware
│ └── types/ # TypeScript Definitions
├── public/ # Static Assets
└── supabase_setup.sql # Database Schema & RLS Policiesgit clone <your-repo-url>
cd SmartBookMarknpm installCreate a .env.local file in the root directory:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_keyRun the provided supabase_setup.sql in your Supabase SQL Editor. This will:
- Create the
bookmarkstable. - Enable RLS and set up security policies.
- Enable Realtime for the table.
npm run dev- Problem: Bookmark list updates in real-time without page refresh (if you open two tabs and add a bookmark in one, it should appear in the other). Initially, changes made in session A were not reflected in session B without a manual refresh.
- Solution: Implemented Supabase Realtime by subscribing to
postgres_changes. The application now listens for allINSERT,UPDATE, andDELETEevents on thebookmarkstable and synchronizes the UI state across all active tabs instantly.
Problem: Ensuring User A cannot see or delete User B's bookmarks.
Solution: Leveraged Supabase's Row Level Security (RLS). Policies were created to restrict SELECT, INSERT, and DELETE operations based on the auth.uid(), making data privacy a core part of the database architecture.
- Problem: The Supabase client was being recreated on every render, causing the WebSocket connection to drop and reconnect constantly.
- Solution: Stabilized the Supabase client instance using React's
useStatehooks to ensure a persistent connection across renders.
- Problem: In some environments, WebSockets (used for Realtime) are blocked, resulting in a permanent
TIMEOUTorCLOSEDstatus. - Solution: Implemented an Automatic Polling Fallback. If the realtime status is not
SUBSCRIBED, the application automatically refreshes the bookmark list every 5 seconds, ensuring a seamless experience even without a live WebSocket connection.
- Problem: Deleting a bookmark felt slow because it waited for the database confirmation.
- Solution: Used Optimistic UI updates to remove the bookmark from the screen immediately while the API call is still in progress, with a silent rollback if it fails.
This app is ready to be deployed on Vercel.
- Push the code to GitHub.
- Connect the repository to Vercel.
- Add the environment variables (
NEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_ANON_KEY) in the Vercel project settings.