A real-time multiplayer chat app for deciding where to eat dinner, featuring AI-assisted restaurant recommendations, a shared shortlist with voting, and an interactive map.
- Real-time Group Chat: Chat with friends in real-time powered by Convex subscriptions
- AI Restaurant Assistant: Mention
@aito get restaurant recommendations, add places to the shortlist, and more - Live Voting: Vote on shortlisted restaurants and see votes update in real-time
- Interactive Map: See restaurant locations on a map with highlighted pins
- No Auth Required: Just enter a display name and start chatting
- TanStack Start - Full-stack React framework
- TanStack AI - Streaming AI responses with tool calling
- Convex - Real-time backend with subscriptions
- Anthropic Claude - AI model for chat (configurable)
- Tailwind CSS - Styling
- Node.js 18+
- pnpm (or npm/yarn)
- Convex account
- Anthropic API key (or other LLM provider)
- Install dependencies:
pnpm install- Set up Convex:
npx convex devThis will prompt you to create or link a Convex project.
- Configure environment variables:
Create a .env.local file:
# Convex
CONVEX_DEPLOYMENT=<your-deployment-name>
VITE_CONVEX_URL=https://<your-deployment>.convex.cloud
# AI Provider
ANTHROPIC_API_KEY=<your-anthropic-key>
# Google API (one key for Places API and Maps)
GOOGLE_API_KEY=<your-google-key> # Server-side (Convex Places API)
VITE_GOOGLE_API_KEY=<your-google-key> # Client-side (Google Maps)Google Cloud Setup:
-
Create a project in Google Cloud Console
-
Enable Places API (New) and Maps JavaScript API
-
Create an API key
-
Add billing (required for Places API)
-
Start the development server:
pnpm dev- Open http://localhost:3000 in your browser
- Enter your display name on the landing page
- Start chatting! Messages are visible to everyone in real-time
- Mention
@aito interact with the AI assistant:@ai find Thai restaurants nearby@ai add Pok Pok to the shortlist@ai show me where Le Pigeon is@ai we can't decide, you pick!
- Vote on restaurants in the shortlist
- See locations on the map
The AI assistant can:
- Search Restaurants: Find restaurants by cuisine, type, or general query
- Get Details: Show detailed info about a specific restaurant
- Add to Shortlist: Add restaurants to the group's voting list
- Remove from Shortlist: Remove restaurants from consideration
- Show on Map: Pan the map to a specific restaurant
- Highlight Items: Draw attention to specific restaurants
The Google API keys (GOOGLE_API_KEY for server-side and VITE_GOOGLE_API_KEY for client-side) are required for the app to function. Without them, restaurant search will return empty results and the map will show a placeholder.
messages- Chat messages with sender info and AI flagshortlist- Restaurants added for group considerationvotes- User votes on shortlisted restaurants
src/
├── components/dinner/ # UI components
│ ├── Chat/ # Chat panel components
│ ├── Map/ # Map components
│ └── Shortlist/ # Voting components
├── stores/ # Zustand stores
│ ├── useVisitorStore.ts # User identity state
│ ├── useMapStore.ts # Map state (center, zoom, highlight)
│ ├── useLocationStore.ts # User geolocation
│ └── useChatStore.ts # Chat state (threadId, messages, status)
├── lib/ # Utilities and hooks
│ ├── useDinnerChat.ts # Composed chat hook
│ ├── useChatMessages.ts # Message subscription
│ ├── useChatInput.ts # Input state management
│ ├── useClientTools.ts # Client-side tool handlers
│ └── location.ts # Geolocation utilities
├── routes/ # TanStack Router routes
│ └── index.tsx # Main app page
convex/
├── schema.ts # Database schema
├── chat.ts # Chat/thread functions
├── shortlist.ts # Shortlist functions
├── votes.ts # Voting functions
├── places.ts # Google Places actions
└── dinnerAgent.ts # AI agent definition
MIT