Skip to content

Latest commit

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date

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

MethodEndpointAuthDescriptionRequest BodyResponse
POST/auth/signupRegister a new user{ name, email, password }{ token, user }
POST/auth/loginAuthenticate user{ email, password }{ token, user }
GET/eventsGet user's events-Event[]
POST/eventsCreate a new event{ title, startTime, endTime, status? }Event
PUT/events/:idUpdate an event{ title?, startTime?, endTime?, status? }Event
DELETE/events/:idDelete an event-{ ok: true }
GET/swappable-slotsGet other users' swappable slots-Event[]
POST/swap-requestCreate a swap request{ mySlotId, theirSlotId }SwapRequest
POST/swap-response/:requestIdAccept/reject swap request{ accept: boolean }{ ok: true }
GET/requests/incomingGet incoming swap requests-SwapRequest[]
GET/requests/outgoingGet outgoing swap requests-SwapRequest[]
GET/healthHealth 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

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages