Managing court reservations at badminton facilities often involves manual tracking, confusion about availability, and unfair queue systems. This project was born from the need to create a fair, transparent, and automated solution that gives all players equal access to courts while eliminating the chaos of manual scheduling. The goal was to build a system where players can see exactly when courts are available, join queues seamlessly, and trust that the system will handle their turn automatically.
- Google OAuth 2.0 integration for seamless sign-in
- JWT token-based session management
- Automatic user profile creation and management
- Live court status updates (Available/In Use)
- Multi-court support with individual tracking
- Color-coded visual indicators (Green: Available, Red: In Use)
- Precise countdown timers for active sessions
- Fair queue positioning for all users
- One active reservation per user/group policy
- Automatic queue advancement when courts become available
- Visual queue position tracking
- Create groups with unique codes (e.g., "alpha-fire-ocean")
- Join existing groups via code sharing
- Group-wide restrictions (one reservation/session per group)
- Automatic group cleanup when empty
- 30-minute court sessions with automatic timers
- Auto-release when timer expires
- Manual early release option
- Automatic queue progression to next player
- Unauthenticated users can view court status
- Real-time availability updates every 5 seconds
- Queue visibility without login required
- Node.js with Express.js - REST API server
- SQLite - Lightweight relational database
- Passport.js - Google OAuth 2.0 authentication
- JWT (jsonwebtoken) - Stateless authentication tokens
- CORS - Cross-origin resource sharing for frontend/backend communication
- React 18 with TypeScript - Type-safe component development
- Vite - Fast build tool and development server
- Tailwind CSS 4 - Utility-first styling framework
- React Context API - Global state management for auth and groups
badminton-reservation-app/
βββ backend/
β βββ server.js # Express server and API routes
β βββ database.js # SQLite database wrapper
β βββ auth.js # Passport OAuth configuration
β βββ utils/
β β βββ utils.js # Helper functions
β βββ badminton.db # SQLite database file
β βββ package.json
β
βββ badminton-reserve-app/ # Frontend application
β βββ src/
β β βββ components/ # React components
β β β βββ CourtTabs.tsx
β β β βββ AvailableTimes.tsx
β β β βββ GroupHeader.tsx
β β β βββ CreateGroupCard.tsx
β β β βββ JoinGroupCard.tsx
β β β βββ ...
β β βββ contexts/
β β β βββ AuthContext.tsx
β β βββ hooks/
β β β βββ useGroupManagement.ts
β β βββ types/
β β β βββ group.ts
β β βββ utils/
β β β βββ api.ts
β β βββ App.tsx # Main application component
β β βββ main.tsx # Application entry point
β βββ package.json
β
βββ assets/
β βββ img/
β βββ badminton-reserve-app.jpeg
β
βββ README.md
- User clicks "Sign in with Google"
- Backend redirects to Google OAuth consent screen
- Google returns user profile to backend callback URL
- Backend generates JWT token with user ID, email, and name
- Frontend stores token and uses it for all authenticated API requests
- Joining Queue: User selects a court and joins the queue (assigned next available position)
- Queue Management: System maintains ordered queue per court with positions (1, 2, 3...)
- Taking Court: When a court is available, users can manually take it OR queue auto-advances
- Auto-Advance: When a session expires, the first person in queue automatically starts their 30-minute session
- Timer Expiration: After 30 minutes, court automatically releases and next person in queue starts
- Group Creation: User creates group β receives unique 3-word code (e.g., "delta-mountain-eagle")
- Group Joining: Other users enter code to join the same group
- Group Restrictions:
- Only one member can have an active reservation at a time
- Only one member can use a court at a time
- Prevents group from monopolizing multiple courts
- Group Leaving: Members can leave anytime; empty groups auto-delete
- Frontend polls court status every 1-5 seconds
- Session cleanup runs every 5 seconds on backend
- Expired sessions trigger automatic queue advancement
- All users see synchronized state updates
- Recreational Badminton Facilities: Gyms, community centers, and sports clubs can automate court bookings
- University Recreation Centers: Fair queue system for student access to courts
- Private Badminton Clubs: Member management with group play support
- Tournament Warm-Up Areas: Organize practice court access during events
- Multi-Sport Facilities: Adaptable to tennis, squash, or other court-based sports
This project evolved through several key phases:
- Initial Authentication: Started with Google OAuth integration and JWT token system
- Court Management: Built real-time court status tracking with SQLite database
- Timer System: Implemented 30-minute sessions with automatic expiration cleanup
- Queue Mechanism: Developed fair queue positioning and automatic advancement
- Group Feature: Added group management to support friend groups playing together
- Public Access: Opened court status viewing to unauthenticated users
- Deployment: Configured for production with Vercel (frontend) and backend hosting
Key technical challenges solved:
- Race Conditions: Preventing double-bookings when multiple users join queue simultaneously
- Timer Synchronization: Ensuring accurate countdown across time zones
- Automatic Queue Progression: Reliably advancing queue when sessions expire
- Group Restrictions: Enforcing one-reservation and one-session per group rules
- CORS Configuration: Allowing secure communication between frontend and backend on different domains
- Node.js (v16 or higher)
- npm or yarn
- Google Cloud Console project with OAuth 2.0 credentials
- Navigate to backend directory:
cd backend- Install dependencies:
npm install- Create
.envfile with the following variables:
PORT=3001
SESSION_SECRET=your_session_secret_here
JWT_SECRET=your_jwt_secret_here
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
FRONTEND_URL=http://localhost:5173- Start the server:
npm start
# or for development with auto-reload:
npm run dev- Navigate to frontend directory:
cd badminton-reserve-app- Install dependencies:
npm install- Create
.envfile:
VITE_API_URL=http://localhost:3001- Start development server:
npm run dev- Open browser to
http://localhost:5173
The SQLite database will be automatically created on first run with the following tables:
users- User profiles from Google OAuthcourts- Court definitions (Courts 1-3)reservations- Queue positions for each courtcourt_sessions- Active 30-minute sessionsgroups- Group definitions with unique codesgroup_members- Many-to-many relationship between users and groups
- Push Notifications: Alert users when their queue position is approaching or court is ready
- Email Notifications: Send confirmation emails for reservations and session starts
- Admin Dashboard: Facility management interface for creating/deactivating courts, viewing analytics
- Booking History: Allow users to view their past court usage and statistics
- Dynamic Session Duration: Let admins configure custom session lengths (15, 30, 60 minutes)
- Mobile App: Native iOS/Android apps with better real-time notifications
- Calendar Integration: Sync reservations with Google Calendar or iCal
- Payment Integration: Add Stripe/PayPal for paid court reservations
- Court Equipment Checkout: Track shuttlecocks, nets, and other equipment
- Player Ratings: Skill-based matchmaking for finding partners
- Tournament Mode: Special scheduling for organized competitions
- Multi-Facility Support: Expand to support multiple locations under one system
- Analytics Dashboard: Usage statistics, peak times, and user engagement metrics
Built with modern web technologies for reliable, real-time court management.
