Skip to content

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.

Notifications You must be signed in to change notification settings

Devgambo/SlotSwapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SlotSwapper

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.

🎯 Project Goals

  • 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

πŸ› οΈ Tech Stack

Frontend (Client)

  • 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)

Backend (Server)

  • 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)

πŸ—οΈ Architecture

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)    β”‚
                                                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

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

πŸ“‹ Overview & Design Choices

Core Features

  1. 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
  2. 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
  3. 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
  4. Request Management

    • Incoming requests: View requests sent to you
    • Outgoing requests: View requests you've sent
    • Status tracking: PENDING, ACCEPTED, REJECTED

Design Choices

  1. Status-Based Event Management: Events use explicit status enums (EventStatus, SwapStatus) to track lifecycle states, preventing invalid state transitions.

  2. MongoDB Transactions: Swap acceptance uses MongoDB transactions to ensure atomicity when exchanging slot owners. This prevents race conditions and ensures data integrity.

  3. JWT Authentication: Stateless authentication using JWT tokens allows for scalable server architecture without session storage.

  4. Client-Side API Abstraction: Centralized API client (api.ts) handles token management, error handling, and request formatting, reducing code duplication.

  5. Dark Mode Support: Built-in dark mode support using Tailwind CSS custom properties for seamless theme switching.

  6. TypeScript: Full TypeScript support on the client side for type safety and better developer experience.

  7. RESTful API: Clean REST API design with semantic HTTP methods and status codes.

πŸš€ Setup & Installation

Prerequisites

  • Node.js 18 or higher
  • MongoDB database (local or cloud instance like MongoDB Atlas)
  • npm or yarn package manager

Step-by-Step Setup

1. Clone the Repository

git clone <repository-url>
cd SlotSwapper

2. Server Setup

  1. Navigate to the server directory:
cd server
  1. Install dependencies:
npm install
  1. 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:3000

Note: Replace your_mongodb_connection_string with your MongoDB URI. Example:

  • Local: mongodb://localhost:27017/slotswapper
  • Atlas: mongodb+srv://username:password@cluster.mongodb.net/slotswapper
  1. Start the development server:
npm run dev

The server will start on http://localhost:4000. You should see:

[SERVER] βœ“ Server listening on http://localhost:4000
[SERVER] Health check: http://localhost:4000/health

3. Client Setup

  1. Open a new terminal and navigate to the client directory:
cd client
  1. Install dependencies:
npm install
  1. (Optional) Create environment file (client/.env.local):
NEXT_PUBLIC_API_BASE=http://localhost:4000

Note: If not set, the client defaults to http://localhost:4000.

  1. Start the development server:
npm run dev

The client will start on http://localhost:3000.

4. Access the Application

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

πŸ“‘ API Documentation

Base URL

http://localhost:4000/api

Authentication

All protected endpoints require a JWT token in the Authorization header:

Authorization: Bearer <your_jwt_token>

Endpoints

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 }

Request/Response Examples

Sign Up

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"
  }
}

Create Event

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"
}

Create Swap Request

POST /api/swap-request
Authorization: Bearer <token>
Content-Type: application/json

{
  "mySlotId": "507f1f77bcf86cd799439011",
  "theirSlotId": "507f1f77bcf86cd799439012"
}

Accept Swap Request

POST /api/swap-response/507f1f77bcf86cd799439013
Authorization: Bearer <token>
Content-Type: application/json

{
  "accept": true
}

Data Models

Event

{
  _id: string;
  title: string;
  startTime: Date;
  endTime: Date;
  status: 'BUSY' | 'SWAPPABLE' | 'SWAP_PENDING';
  owner: ObjectId; // Reference to User
  createdAt: Date;
  updatedAt: Date;
}

SwapRequest

{
  _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;
}

⭐ Bonus Features

This project includes three bonus features that enhance the application:

1. Unit/Integration Tests

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 test

Test Files:

  • server/src/__tests__/swaps.test.js - Comprehensive swap API tests
  • server/src/__tests__/setup.js - Test database setup utilities
  • server/src/__tests__/helpers.js - Test helper functions

2. Real-time Notifications (WebSockets)

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

3. Containerization (Docker)

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 -d

Development (with hot-reload):

docker-compose -f docker-compose.dev.yml up

Services:

  • mongodb - MongoDB database on port 27017
  • server - Express API server on port 4000
  • client - Next.js frontend on port 3000

Docker Files:

  • docker-compose.yml - Production setup
  • docker-compose.dev.yml - Development setup with hot-reload
  • server/Dockerfile - Server production image
  • server/Dockerfile.dev - Server development image
  • client/Dockerfile - Client production image
  • client/Dockerfile.dev - Client development image

πŸ” Assumptions & Challenges

Assumptions

  1. MongoDB Availability: Assumes MongoDB is accessible and properly configured. The application does not handle database connection failures gracefully in production (would need retry logic).

  2. 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.

  3. Single Client Origin: The default CORS configuration allows a single client origin. For production, configure multiple origins or use environment-based origin lists.

  4. Event Ownership: Assumes that once an event is created, only the owner can modify or delete it. No shared ownership or delegation features.

  5. Time Slot Validation: The application does not validate that endTime is after startTime at the API level (validation should be added).

  6. No Overlapping Prevention: The application does not prevent users from creating overlapping time slots for themselves.

Challenges Faced

  1. 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.

  2. 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.

  3. 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.

  4. Type Safety: Maintaining type safety between client and server. Solution: Used TypeScript on the client side with explicit type definitions for API responses.

  5. Error Handling: Providing meaningful error messages to users while maintaining security. Solution: Centralized error handling middleware with sanitized error responses.

  6. 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.

About

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.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published