Echo is a modern, full-featured book reading tracker that helps you organize your reading journey, discover new books, and connect with fellow readers.
- Organize books into three categories: Want to Read, Currently Reading, and Finished
- Multiple view modes: Grid and List layouts with preference persistence
- Hybrid book search (internal database + Open Library API fallback)
- Track reading progress with page counts and completion percentages
- Progress tracking with visual progress bars
- 5-star rating system for finished books
- Write and manage book reviews (public or private)
- Celebrate reading milestones
- Follow other readers to see their activity
- Share reviews and reading progress
- Activity feed showing what friends are reading
- User profiles with reading statistics
- Multi-language support using next-intl
- Fully localized interface
- Easy to add new languages
- Beautiful, responsive design with Tailwind CSS v4
- shadcn/ui component library for consistent styling
- Dark mode support
- Lucide icons throughout
- Smooth animations and transitions
- Next.js 16.0.5 - React framework with App Router
- TypeScript - Type-safe development
- Tailwind CSS v4 - Utility-first styling
- shadcn/ui - High-quality component library
- next-intl - Internationalization
- lucide-react - Icon library
- sonner - Toast notifications
- PostgreSQL - Primary database
- Drizzle ORM - Type-safe database queries
- Clerk - Authentication and user management
- Open Library API - External book data source
- Node.js 18+ and pnpm
- PostgreSQL database
- Clerk account for authentication
- Clone the repository:
git clone <repository-url>
cd echo- Install dependencies:
pnpm install- Set up environment variables:
Create a
.envfile in the root directory with the following variables:
# Database
DATABASE_URL="postgresql://..."
# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_..."
CLERK_SECRET_KEY="sk_..."
# Clerk URLs (optional, can use defaults)
NEXT_PUBLIC_CLERK_SIGN_IN_URL="/"
NEXT_PUBLIC_CLERK_SIGN_UP_URL="/"STRIPE_SECRET_KEY=sk_test_... NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_... STRIPE_WEBHOOK_SECRET=whsec_...
RESEND_API_KEY=re_... RESEND_FROM_EMAIL=noreply@yourdomain.com
NEXT_PUBLIC_BASE_URL=http://localhost:3000
Where to Get Each Variable
- Stripe Keys (STRIPE_SECRET_KEY & NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY)
Steps:
- Go to https://stripe.com and create an account (or log in)
- You'll start in Test Mode (recommended for development)
- Go to Developers → API Keys
- Copy:
- Secret key → STRIPE_SECRET_KEY (starts with sk_test_)
- Publishable key → NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY (starts with pk_test_)
- Stripe Webhook Secret (STRIPE_WEBHOOK_SECRET)
You'll set this up after creating your webhook endpoint. For now, you can skip it and add it later when testing webhooks locally.
To get it later:
-
In Stripe Dashboard → Developers → Webhooks
-
Click Add endpoint
-
For local testing, you'll use Stripe CLI (see below)
-
Resend API Key (RESEND_API_KEY)
Steps:
- Go to https://resend.com and sign up
- After signing in, go to API Keys
- Click Create API Key
- Give it a name (e.g., "Echo Development")
- Copy the key → RESEND_API_KEY (starts with re_)
- Resend From Email (RESEND_FROM_EMAIL)
Steps:
- In Resend dashboard, go to Domains
- Add and verify your domain (e.g., yourdomain.com)
- Follow DNS verification steps
- Once verified, you can use emails like:
For testing without a domain:
- Resend provides onboarding@resend.dev for testing
- Use: RESEND_FROM_EMAIL=onboarding@resend.dev
⚠️ This only works for sending to your own email address
- Base URL (NEXT_PUBLIC_BASE_URL)
For local development: NEXT_PUBLIC_BASE_URL=http://localhost:3000
For production: NEXT_PUBLIC_BASE_URL=https://yourdomain.com
Testing Stripe Webhooks Locally
To test webhooks during development, use the Stripe CLI:
brew install stripe/stripe-cli/stripe
stripe login
stripe listen --forward-to localhost:3000/api/webhooks/stripe
This command will output a webhook signing secret like whsec_... - use that for STRIPE_WEBHOOK_SECRET.
- Set up the database:
# Generate migrations
pnpm drizzle-kit generate
# Push schema to database
pnpm drizzle-kit push- Run the development server:
pnpm dev- Open http://localhost:3000 in your browser.
src/
app/
[locale]/ # Localized routes
actions/ # Server actions
books/ # Book-related pages
feed/ # Activity feed
library/ # User library
profile/ # User profile
users/ # User search
globals.css # Global styles
layout.tsx # Root layout
components/ # React components
ui/ # shadcn/ui components
db/
schema.ts # Database schema
hooks/ # Custom React hooks
i18n/ # Internationalization config
lib/ # Utility functions
types/ # TypeScript types
messages/ # Translation files
en.json # English translations
Echo uses the following main tables:
- users - User profiles (synced with Clerk)
- books - Book information
- user_books - User's library with reading status and progress
- reviews - Book reviews
- follows - Social follow relationships
Echo implements a smart hybrid search strategy:
- First searches your internal database for books you and others have added
- Falls back to Open Library API only when no internal matches found
- Shows visual indicators for data source (Database vs. External)
New users are prompted to set a username with a non-dismissible dialog, ensuring all users have proper profiles before accessing the app.
Users can switch between grid and list views in their library, with preferences saved to localStorage for persistence.
# Development server
pnpm dev
# Build for production
pnpm build
# Start production server
pnpm start
# Database commands
pnpm drizzle-kit generate # Generate migrations
pnpm drizzle-kit push # Push schema to database
pnpm drizzle-kit studio # Open Drizzle Studioshadcn/ui components can be added using:
pnpm dlx shadcn@latest add <component-name>- Add new keys to
messages/en.json - Create new language files in
messages/directory - Update
src/i18n/routing.tsto include new locales
Contributions are welcome! Please feel free to submit a Pull Request.
- Book data provided by Open Library
- Authentication powered by Clerk
- UI components from shadcn/ui
- Icons from Lucide