A mobile-first web application that allows groups of people (in-person or remote) to submit items for tasting and rank them against each other.
DRanked enables collaborative tasting events where:
- Host creates an event with a unique join code
- Guests join using the event code and their name
- Anyone can add items to taste
- Everyone rates items on a 1-10 scale
- Results are compiled in real-time
Perfect for beer tastings, wine nights, whiskey flights, and more!
- Next.js 16 with App Router
- React 19 with TypeScript
- Tailwind CSS 4 for styling
- Mobile-first responsive design
- PostgreSQL database
- Next.js API Routes for server-side logic
- pg library for database connections
- TypeScript for type safety
- ESLint for code quality
- Vitest for testing
- Node.js 18+
- PostgreSQL database
- npm or yarn
- Clone the repository:
git clone <repository-url>
cd dranked- Install dependencies:
npm install- Set up your database:
# Create a PostgreSQL database
createdb dranked
# Set your database URL
echo "DATABASE_URL=postgresql://username:password@localhost:5432/dranked" > .env.local- Initialize the database schema:
psql -d dranked -f src/utils/schema.sql- Start the development server:
npm run dev- Open http://localhost:3000 in your browser
- Event Types: Beer, Wine, Whiskey
- Tasting Styles:
- Open - participants can see item details
- Blind - item details are hidden during tasting
- Flexible Duration: Events can run for weeks (e.g., "Fresh Hop Season")
- Item Limit: Up to 250 items per event (typical: 10-50)
- Simple Join Process: Just event code + name
- Mobile Optimized: Large touch targets, one-handed operation
- Collaborative: Any participant can add items
- Real-time Updates: Live updates as users add items and ratings
- Host Control: Secure admin access with cryptographic tokens
- Guest Access: Simple 6-character join codes
- No Accounts: Name-based identity within event scope
- events - Event metadata, join codes, host tokens
- items - Beverages/items being tasted
- users - Event participants
- ratings - User scores (1-10) for items
See lib/schema.sql for complete schema definition.
/src/app/ # Next.js App Router pages
├── page.tsx # Home page - event creation
├── /api/ # API routes
└── /event/[id]/ # Event pages
/src/utils/ # Business logic layer
├── db.ts # Database connection
├── schema.sql # Database schema
├── /db/ # Database operations
└── /api/ # API client functions
/types/ # TypeScript definitions
POST /api/event/create- Create new event- Body:
{ hostName, eventName, beverageType, tastingStyle } - Returns: Event with join code, host token, and host user
- Body:
GET /api/event/[id]- Get event details- Returns: Basic event info (name, host, beverage type, join code)
GET /api/event/[id]/items- List event itemsPOST /api/event/[id]/add-item- Add new item- Body:
{ name, producer?, year?, type?, addedByUserId, addedByName }
- Body:
PUT /api/event/[id]/edit-item- Update existing item- Body:
{ itemId, name, producer?, year?, type? }
- Body:
POST /api/users- Join event as user- Body:
{ eventId, name } - Returns: User record with ID
- Body:
POST /api/ratings- Submit/update rating- Body:
{ eventId, itemId, userId, score }
- Body:
/- Home page- Create new event form
- Recent events list (from localStorage)
/join/[code]- Join event with 6-character code- Enter name to join
- Creates user record
/event/[id]- Event home page- View items list
- Add new items
- Edit items
- No authentication required
/event/[id]/add- Add item form- Requires user in localStorage
- Redirects to join if no user
/event/[id]/edit?itemId=[id]- Edit item form- Updates existing item details
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run test- Run testsnpm run test:ui- Run tests with UInpm run lint- Run ESLint
Unit tests are written with Vitest and located alongside implementation files:
npm run test # Run all tests
npm run test:ui # Interactive test UICreate .env.local with:
DATABASE_URL=postgresql://username:password@localhost:5432/dranked