SlotSwapper is a peer-to-peer time-slot scheduling application that enables users to create, manage, and swap time slots with other users. Whether you're coordinating meetings, events, or appointments, SlotSwapper facilitates seamless time-slot exchanges between users.
- User Management: Secure authentication and user account management
- Event Scheduling: Create and manage personal time slots with flexible status management
- Peer-to-Peer Swapping: Enable users to request and respond to time-slot swap requests
- Real-time Status Tracking: Track event statuses (BUSY, SWAPPABLE, SWAP_PENDING) throughout the swap lifecycle
- Atomic Operations: Ensure data consistency during swap transactions using database transactions
- Framework: Next.js 16 (App Router)
- UI Library: React 19
- Language: TypeScript 5
- Styling: Tailwind CSS 4
- Icons: Lucide React
- Notifications: Sonner (toast notifications)
- WebSockets: Socket.IO Client for real-time updates
- Build Tool: Webpack (via Next.js)
- Runtime: Node.js 18+
- Framework: Express.js 4
- Database: MongoDB with Mongoose ODM
- Authentication: JWT (JSON Web Tokens)
- Password Hashing: bcryptjs
- CORS: Express CORS middleware
- Logging: Morgan (HTTP request logger)
- WebSockets: Socket.IO for real-time notifications
- Testing: Jest, Supertest, MongoDB Memory Server
- Environment: ES Modules (ESM)
SlotSwapper follows a client-server architecture with clear separation of concerns:
βββββββββββββββββββ HTTP/REST API βββββββββββββββββββ
β βββββββββββββββββββββββββββββββββΊβ β
β Next.js Client β (JWT Authentication) β Express Server β
β (Port 3000) β β (Port 4000) β
β β β β
βββββββββββββββββββ βββββββββββββββββββ
β
β
βΌ
βββββββββββββββββββ
β MongoDB β
β (Database) β
βββββββββββββββββββ
SlotSwapper/
βββ client/ # Next.js frontend application
β βββ src/
β β βββ app/ # Next.js App Router pages
β β β βββ dashboard/ # User dashboard
β β β βββ login/ # Login page
β β β βββ signup/ # Signup page
β β β βββ marketplace/ # Browse swappable slots
β β β βββ requests/ # View swap requests
β β βββ components/ # Reusable React components
β β βββ lib/ # Client-side utilities (API client)
β βββ package.json
β
βββ server/ # Express.js backend API
βββ src/
β βββ models/ # Mongoose models (User, Event, SwapRequest)
β βββ routes/ # API route handlers
β βββ middleware/ # Authentication middleware
β βββ lib/ # Database connection utilities
β βββ server.js # Express app configuration
β βββ index.js # Server entry point
βββ package.json
-
User Authentication
- JWT-based authentication with secure password hashing (bcryptjs)
- Token stored in browser localStorage for client-side requests
- Bearer token authentication for API requests
-
Event Management
- Users can create, update, and delete their time slots
- Three status states:
BUSY,SWAPPABLE,SWAP_PENDING - Events are owned by specific users and can be marked as swappable
-
Swap System
- Users can browse other users' swappable slots
- Request system: Users can send swap requests (mySlot β theirSlot)
- Response system: Recipients can accept or reject swap requests
- Atomic transactions: Swap acceptance uses MongoDB transactions to ensure data consistency
-
Request Management
- Incoming requests: View requests sent to you
- Outgoing requests: View requests you've sent
- Status tracking: PENDING, ACCEPTED, REJECTED
-
Status-Based Event Management: Events use explicit status enums (
EventStatus,SwapStatus) to track lifecycle states, preventing invalid state transitions. -
MongoDB Transactions: Swap acceptance uses MongoDB transactions to ensure atomicity when exchanging slot owners. This prevents race conditions and ensures data integrity.
-
JWT Authentication: Stateless authentication using JWT tokens allows for scalable server architecture without session storage.
-
Client-Side API Abstraction: Centralized API client (
api.ts) handles token management, error handling, and request formatting, reducing code duplication. -
Dark Mode Support: Built-in dark mode support using Tailwind CSS custom properties for seamless theme switching.
-
TypeScript: Full TypeScript support on the client side for type safety and better developer experience.
-
RESTful API: Clean REST API design with semantic HTTP methods and status codes.
- Node.js 18 or higher
- MongoDB database (local or cloud instance like MongoDB Atlas)
- npm or yarn package manager
git clone <repository-url>
cd SlotSwapper- Navigate to the server directory:
cd server- Install dependencies:
npm install- Create environment file (
server/.env):
PORT=4000
MONGO_URI=your_mongodb_connection_string
JWT_SECRET=your_secret_key_change_this_in_production
CLIENT_ORIGIN=http://localhost:3000Note: Replace your_mongodb_connection_string with your MongoDB URI. Example:
- Local:
mongodb://localhost:27017/slotswapper - Atlas:
mongodb+srv://username:password@cluster.mongodb.net/slotswapper
- Start the development server:
npm run devThe server will start on http://localhost:4000. You should see:
[SERVER] β Server listening on http://localhost:4000
[SERVER] Health check: http://localhost:4000/health
- Open a new terminal and navigate to the client directory:
cd client- Install dependencies:
npm install- (Optional) Create environment file (
client/.env.local):
NEXT_PUBLIC_API_BASE=http://localhost:4000Note: If not set, the client defaults to http://localhost:4000.
- Start the development server:
npm run devThe client will start on http://localhost:3000.
Open your browser and navigate to:
http://localhost:3000
You should see the SlotSwapper homepage. From here, you can:
- Sign up for a new account
- Log in with existing credentials
- Create and manage events
- Browse and request slot swaps
http://localhost:4000/api
All protected endpoints require a JWT token in the Authorization header:
Authorization: Bearer <your_jwt_token>
| Method | Endpoint | Auth | Description | Request Body | Response |
|---|---|---|---|---|---|
POST |
/auth/signup |
β | Register a new user | { name, email, password } |
{ token, user } |
POST |
/auth/login |
β | Authenticate user | { email, password } |
{ token, user } |
GET |
/events |
β | Get user's events | - | Event[] |
POST |
/events |
β | Create a new event | { title, startTime, endTime, status? } |
Event |
PUT |
/events/:id |
β | Update an event | { title?, startTime?, endTime?, status? } |
Event |
DELETE |
/events/:id |
β | Delete an event | - | { ok: true } |
GET |
/swappable-slots |
β | Get other users' swappable slots | - | Event[] |
POST |
/swap-request |
β | Create a swap request | { mySlotId, theirSlotId } |
SwapRequest |
POST |
/swap-response/:requestId |
β | Accept/reject swap request | { accept: boolean } |
{ ok: true } |
GET |
/requests/incoming |
β | Get incoming swap requests | - | SwapRequest[] |
GET |
/requests/outgoing |
β | Get outgoing swap requests | - | SwapRequest[] |
GET |
/health |
β | Health check endpoint | - | { ok: true } |
POST /api/auth/signup
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com",
"password": "securepassword123"
}Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "507f1f77bcf86cd799439011",
"name": "John Doe",
"email": "john@example.com"
}
}POST /api/events
Authorization: Bearer <token>
Content-Type: application/json
{
"title": "Team Meeting",
"startTime": "2024-01-15T10:00:00Z",
"endTime": "2024-01-15T11:00:00Z",
"status": "BUSY"
}POST /api/swap-request
Authorization: Bearer <token>
Content-Type: application/json
{
"mySlotId": "507f1f77bcf86cd799439011",
"theirSlotId": "507f1f77bcf86cd799439012"
}POST /api/swap-response/507f1f77bcf86cd799439013
Authorization: Bearer <token>
Content-Type: application/json
{
"accept": true
}{
_id: string;
title: string;
startTime: Date;
endTime: Date;
status: 'BUSY' | 'SWAPPABLE' | 'SWAP_PENDING';
owner: ObjectId; // Reference to User
createdAt: Date;
updatedAt: Date;
}{
_id: string;
requester: ObjectId; // Reference to User
recipient: ObjectId; // Reference to User
mySlot: ObjectId; // Reference to Event
theirSlot: ObjectId; // Reference to Event
status: 'PENDING' | 'ACCEPTED' | 'REJECTED';
createdAt: Date;
updatedAt: Date;
}This project includes three bonus features that enhance the application:
Comprehensive test suite using Jest, Supertest, and MongoDB Memory Server:
- Test Coverage: Full test coverage for swap request and response logic
- Integration Tests: Tests for complex transaction-based swap acceptance/rejection
- Unit Tests: Validation tests for all error cases and edge conditions
- Test Utilities: Helper functions for creating test users, events, and swap requests
Run Tests:
cd server
npm testTest Files:
server/src/__tests__/swaps.test.js- Comprehensive swap API testsserver/src/__tests__/setup.js- Test database setup utilitiesserver/src/__tests__/helpers.js- Test helper functions
Instant notifications using Socket.IO for real-time updates:
- Swap Request Notifications: Users are instantly notified when they receive a swap request
- Response Notifications: Users are notified when their swap requests are accepted or rejected
- Automatic UI Updates: Pages automatically refresh when relevant swap events occur
- JWT Authentication: WebSocket connections are authenticated using JWT tokens
- User-Specific Rooms: Each user has their own notification room for targeted messaging
Features:
- Real-time notifications for incoming swap requests
- Instant updates when swap requests are accepted/rejected
- Automatic marketplace and requests page refresh on relevant events
- Secure WebSocket authentication
Full Docker setup for easy deployment and local development:
- Production Dockerfiles: Optimized multi-stage builds for server and client
- Development Dockerfiles: Hot-reload enabled Dockerfiles for development
- Docker Compose: Complete stack orchestration with MongoDB
- Separate Configs: Production and development compose files
Run with Docker:
Production:
docker-compose up -dDevelopment (with hot-reload):
docker-compose -f docker-compose.dev.yml upServices:
mongodb- MongoDB database on port 27017server- Express API server on port 4000client- Next.js frontend on port 3000
Docker Files:
docker-compose.yml- Production setupdocker-compose.dev.yml- Development setup with hot-reloadserver/Dockerfile- Server production imageserver/Dockerfile.dev- Server development imageclient/Dockerfile- Client production imageclient/Dockerfile.dev- Client development image
-
MongoDB Availability: Assumes MongoDB is accessible and properly configured. The application does not handle database connection failures gracefully in production (would need retry logic).
-
JWT Token Storage: Assumes localStorage is available and secure enough for development. In production, consider more secure storage options (httpOnly cookies) or token refresh mechanisms.
-
Single Client Origin: The default CORS configuration allows a single client origin. For production, configure multiple origins or use environment-based origin lists.
-
Event Ownership: Assumes that once an event is created, only the owner can modify or delete it. No shared ownership or delegation features.
-
Time Slot Validation: The application does not validate that
endTimeis afterstartTimeat the API level (validation should be added). -
No Overlapping Prevention: The application does not prevent users from creating overlapping time slots for themselves.
-
Atomic Swap Operations: Ensuring that slot ownership exchange happens atomically to prevent race conditions. Solution: Used MongoDB transactions with session management to ensure all-or-nothing operations.
-
Status Management: Managing event status transitions (BUSY β SWAPPABLE β SWAP_PENDING β BUSY) correctly throughout the swap lifecycle. Solution: Implemented explicit status checks and updates at each stage.
-
Authorization: Ensuring users can only respond to swap requests sent to them and can only modify their own events. Solution: Middleware-based authentication and ownership checks in route handlers.
-
Type Safety: Maintaining type safety between client and server. Solution: Used TypeScript on the client side with explicit type definitions for API responses.
-
Error Handling: Providing meaningful error messages to users while maintaining security. Solution: Centralized error handling middleware with sanitized error responses.
-
State Consistency: Ensuring that when a swap is rejected, both slots return to SWAPPABLE status. Solution: Transaction rollback or explicit status updates in the rejection flow.