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=4000MONGO_URI=your_mongodb_connection_stringJWT_SECRET=your_secret_key_change_this_in_productionCLIENT_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.