A production-ready, full-stack restaurant review application built with Next.js 14, TypeScript, Prisma, and PostgreSQL.
This application is a modern restaurant review platform that allows users to discover restaurants, leave reviews, and manage their dining experiences. Restaurant owners can create and manage their listings, while reviewers can browse, filter, and review restaurants.
Key Highlights:
- 🔐 Secure JWT authentication with role-based access control
- 🎨 Fully responsive design (mobile, tablet, desktop)
- 📊 Comprehensive filtering and sorting with persistence
- 🧪 Three-tier testing: Unit + Component + E2E (~88% merged coverage)
- 📈 E2E coverage collection with nextcov
- 🚀 Built with Next.js 14 App Router and Server Actions
- 💾 PostgreSQL database with Prisma ORM
- ✅ Full TypeScript coverage with Zod validation
✅ User Authentication
- Email/password registration and login
- JWT token-based authentication
- HTTP-only cookies for security
- Role selection (Reviewer or Owner)
✅ Restaurant Owners
- Create, read, update, delete own restaurants
- Upload restaurant images (with validation)
- View all reviews on their restaurants
- Cannot modify other owners' restaurants
✅ Reviewers
- Browse all restaurants with filtering
- Filter by cuisine type and minimum rating
- Sort by best/worst rated
- Leave star ratings (1-5) with comments
- One review per restaurant
- Edit/delete own reviews
✅ Filter Persistence
- Filters and sorting saved to localStorage
- Restored when user returns to the site
- URL-based filtering for sharing
✅ Responsive Design
- Mobile-first approach with Tailwind CSS
- Adapts to all screen sizes
- Touch-friendly interfaces
- Frontend: Next.js 14, React, TypeScript, Tailwind CSS
- Backend: Next.js API Routes, Server Actions
- Database: PostgreSQL (Docker)
- ORM: Prisma
- Authentication: JWT with bcryptjs
- Form Validation: React Hook Form + Zod
- Testing: Vitest (unit + component), Playwright (E2E), nextcov (coverage)
Before you begin, ensure you have the following installed:
- Node.js (v18 or higher)
- Docker Desktop
- Git
Ensure you have the following installed:
# 1. Clone the repository
git clone <your-repo-url>
cd restaurant-reviews-platform
# 2. Install dependencies
npm install
# 3. Set up environment variables
cp .env.example .env
# Edit .env if needed (default values work for local development)
# 4. Set up database (Docker + migrations + seed data)
npm run db:setup
# 5. Start development server
npm run devThe application will be available at http://localhost:3000
The .env file contains the following (default values work out-of-the-box):
DATABASE_URL="postgresql://restaurant_user:restaurant_password@localhost:5433/restaurant_reviews?schema=public"
JWT_SECRET="your-super-secret-jwt-key-change-in-production-8f7d6e5c4b3a2918"
NODE_ENV="development"
NEXTAUTH_URL="http://localhost:3000"JWT_SECRET in production!
After seeding, you can log in with these test accounts:
| Role | Name | Password | |
|---|---|---|---|
| Owner | John Smith | [email protected] | Password123 |
| Owner | Sarah Johnson | [email protected] | Password123 |
| Reviewer | Mike Chen | [email protected] | Password123 |
| Reviewer | Emily Davis | [email protected] | Password123 |
| Reviewer | David Wilson | [email protected] | Password123 |
npm run dev- Start Next.js development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLint
npm test- Run unit + component tests with coveragenpm run test:unit- Run unit tests only (jsdom)npm run test:unit:ui- Run unit tests with Vitest UI dashboardnpm run test:watch- Run unit tests in watch modenpm run test:component- Run component tests (browser)npm run test:component:headed- Run component tests with visible browser
npm run e2e- Run E2E tests with coverage (setup db, run tests, teardown)npm run e2e:headed- Run E2E tests with visible browsernpm run e2e:ui- Run E2E tests with Playwright UInpm run coverage:merge- Merge unit, component, and E2E coverage into single report
npm run db:setup- Initial database setup (Docker + migrations + seed)npm run db:start- Start existing database containernpm run db:stop- Stop database containernpm run db:reset- Reset database (wipe all data and reseed)npm run db:push- Push Prisma schema changesnpm run db:seed- Seed database with sample datanpm run db:studio- Open Prisma Studio GUI
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── (auth)/ # Authentication pages (login, register)
│ │ ├── owner/ # Owner dashboard and features
│ │ ├── reviewer/ # Reviewer pages
│ │ ├── actions/ # Server Actions
│ │ └── api/ # API routes
│ ├── components/ # React components
│ │ ├── restaurants/ # Restaurant-related components
│ │ ├── reviews/ # Review components
│ │ └── ui/ # Reusable UI components
│ ├── lib/ # Utility functions and configurations
│ │ ├── auth.ts # Authentication utilities
│ │ ├── validators.ts # Zod schemas
│ │ └── utils.ts # Helper functions
│ └── types/ # TypeScript type definitions
├── prisma/
│ ├── schema.prisma # Database schema
│ └── seed.js # Database seeding script
├── scripts/ # Database management scripts
├── docker-compose.yml # Docker configuration
└── DATABASE_SETUP.md # Detailed database documentation
Open Prisma Studio to view and edit data visually:
npm run db:studioTo start fresh with clean seed data:
npm run db:resetWarning: This will delete all existing data!
When you're done working:
npm run db:stopThe data persists in a Docker volume, so you can restart with npm run db:start
-
Start the database (first time only):
npm run db:setup
-
Daily development:
npm run db:start # Start database npm run dev # Start app
-
When done:
npm run db:stop # Stop database
- Create and manage restaurants
- Upload restaurant images
- View reviews on their restaurants
- Edit/delete their own restaurants
- Cannot review restaurants
- Browse all restaurants
- Filter by rating and cuisine
- Leave reviews and ratings
- Edit/delete their own reviews
- One review per restaurant
- ARCHITECTURE.md - Detailed architecture, patterns, and design decisions
- DATABASE_SETUP.md - Database setup and management guide
- Prisma Documentation - ORM documentation
- Next.js Documentation - Framework documentation
This project uses a three-tier testing strategy with Vitest for unit and component tests and Playwright for E2E tests, with coverage collection and merging powered by nextcov.
| Test Type | Environment | Best For | Coverage Focus |
|---|---|---|---|
| Unit | jsdom | Server actions, utilities, hooks | Business logic, validation |
| Component | Real browser (Playwright) | UI components, interactions | React components, browser APIs |
| E2E | Full Next.js server | User flows, pages | Server components, integration |
Fast unit tests running in jsdom environment for server actions, utilities, and hooks.
# Run unit tests with coverage
npm run test:unit
# Run tests in watch mode
npm run test:watch
# Run with Vitest UI dashboard
npm run test:unit:uiCoverage contribution:
src/app/actions/*- Server Actions (~80%)src/lib/*- Utilities, auth, validators (~73%)src/hooks/*- Custom hooks (100%)
Real browser tests using Vitest browser mode with Playwright. Components render in an actual browser with real DOM APIs, CSS, and user interactions.
# Run component tests (headless)
npm run test:component
# Run with visible browser for debugging
npm run test:component:headedCoverage contribution:
src/components/auth/*- LoginForm, RegisterForm, LogoutButton (100%)src/components/filters/*- FilterPanel (100%)src/components/ui/*- Button, Input, StarRating (100%)src/components/restaurants/*- RestaurantCard, RestaurantForm (~88%)src/components/reviews/*- ReviewForm (100%)
Screenshots are captured on test failures and saved to __screenshots__/ folders next to test files.
Full end-to-end tests using Playwright that test the complete application including React Server Components, server actions, and user flows.
# Run E2E tests (sets up database, runs tests, tears down)
npm run e2e
# Run E2E tests with headed browser
npm run e2e:headed
# Run E2E tests with Playwright UI
npm run e2e:uiCoverage contribution:
src/app/*/page.tsx- All pages and layouts- React Server Components
- Full authentication flows
- Database operations through the UI
This project uses nextcov to collect V8 coverage from all three test types and merge them into a unified report.
# Run all tests (unit + component)
npm test
# Run E2E tests (includes coverage collection)
npm run e2e
# Merge all coverage sources into a single report
npm run coverage:mergeCoverage Output:
- Unit test coverage:
coverage/unit/ - Component test coverage:
coverage/component/ - E2E test coverage:
coverage/e2e/ - Merged coverage:
coverage/merged/(HTML report atcoverage/merged/index.html)
Coverage by Test Type:
| Test Type | Overall % | What It Covers |
|---|---|---|
| Unit Tests | ~47% | Server actions, lib utilities, hooks |
| Component Tests | ~36% | UI components (100% on tested components) |
| E2E Tests | ~52% | Pages, server components, user flows |
| Merged | ~88% | Complete picture of your application |
Why Three Test Types?
Each test type excels at different aspects:
- Unit tests - Fast, isolated tests for business logic that doesn't need a browser
- Component tests - Real browser rendering for components that use browser APIs (localStorage, CSS, events)
- E2E tests - Full integration testing including React Server Components which can't be unit tested
Test Coverage Highlights:
- ✅ V8 coverage provider for accurate source mapping
- ✅ Unit tests for all server actions and utilities
- ✅ Component tests for all interactive UI components
- ✅ E2E tests for server components and user flows
- ✅ Coverage merging with statement normalization
- ✅ Form validation tests at all levels
- ✅ Authentication and authorization tests
# Build the application
npm run build
# Start production server
npm startRecommended:
- Vercel - Zero-config deployment for Next.js
- Railway - Full-stack with built-in PostgreSQL
- Render - Easy full-stack hosting
Ensure these are set in your production environment:
DATABASE_URL="postgresql://user:password@host:port/database"
JWT_SECRET="<secure-random-string-minimum-32-characters>"
NODE_ENV="production"
NEXTAUTH_URL="https://yourdomain.com"# Apply migrations in production
npx prisma migrate deploy
# (Optional) Seed initial data
npm run db:seed-
Ensure Docker is running:
docker ps
You should see
restaurant-reviews-dbcontainer -
Check database health:
docker exec restaurant-reviews-db pg_isready -U restaurant_user -d restaurant_reviews -
Verify environment variables:
- Check
.envfile has correctDATABASE_URL - Port should be
5433(not5432)
- Check
If port 5433 is in use, either:
- Stop the service using that port
- Change the port in
docker-compose.ymland.env
To completely reset everything:
npm run db:stop
docker volume rm steve-zhang_postgres_data
npm run db:setup- 🔒 Password hashing with bcrypt (10 rounds)
- 🍪 HTTP-only cookies prevent XSS attacks
- 🔑 JWT tokens with 7-day expiration
- ✅ Server-side authorization on all mutations
- 🛡️ Input validation with Zod schemas
- 🚫 SQL injection prevention (Prisma parameterized queries)
- ⚡ React Server Components for better initial load
- 🖼️ Next.js Image optimization with lazy loading
- 📦 Automatic code splitting by route
- 💾 Strategic caching with revalidation
- 🔄 Filter persistence with localStorage
- 📘 100% TypeScript coverage
- 🧪 Three-tier test suite (unit + component + E2E)
- 📏 ESLint + Prettier configuration
- 🏗️ Clean architecture with separation of concerns
- 📝 Inline documentation and comments
This application implements several industry-standard patterns:
- Layered Architecture - Separation of presentation, business logic, and data access
- Server Actions - Type-safe API layer without manual routes
- Role-Based Access Control (RBAC) - Owner and Reviewer roles with different permissions
- Repository Pattern - Prisma as data access abstraction
- Form Validation - Multi-layer validation (client + server)
See ARCHITECTURE.md for detailed documentation.
MIT License - feel free to use this project for learning and development purposes.
For questions or feedback about this project, please open an issue in the repository.