Skip to content
AkenzzPublic

About

πŸš€ Content Management Backend : A production-ready REST API for managing text content and file uploads using Express.js and MongoDB.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Content Management Backend

A production-level backend API for content and file management using Express.js and MongoDB.

Features

  • Text Content Management: Store and retrieve text content with automatic unique ID generation
  • File Upload & Storage: Upload up to 10 files per unique key with secure storage
  • Unique Key Generation: 6-character alphanumeric keys for both content and files
  • Input Validation: Comprehensive validation for all inputs
  • Security: Rate limiting, CORS, helmet security headers, and file size limits
  • Error Handling: Comprehensive error handling and logging
  • File Downloads: Individual file download support with proper content types

API Endpoints

Realtime Lobby and Chat (Socket.IO + REST)

The backend now supports realtime anonymous lobby chat using Socket.IO.

Base URL (local):

Realtime REST Endpoint

6. Get Active Public Lobbies

GET /get-it/lobbies/public

Returns all public lobbies that are currently active.

Response:

{
  "success": true,
  "lobbies": [
    {
      "lobbyId": "AB12CD",
      "lobbyName": "Friday Room",
      "currentUsers": 2,
      "maxUsers": 6,
      "status": "open",
      "createdAt": "2026-04-22T10:00:00.000Z"
    }
  ]
}

Socket.IO Connection Flow

  1. Connect socket to server.
  2. Server emits session:created with a temporary sessionId.
  3. Use events below with callback acknowledgments.

Acknowledgment pattern used by this server:

Success Ack:

{
  "success": true,
  "...": "event-specific payload"
}

Error Ack:

{
  "success": false,
  "message": "Reason of failure"
}

Socket.IO Events

Event names are case-sensitive.

Server -> Client
  1. session:created
  • Sent after socket connects.

Payload:

{
  "sessionId": "2e10c5a9-0ec7-45e6-8e0a-b8dbe09efcb5",
  "message": "Temporary anonymous session created"
}
  1. lobby:created
  • Sent to creator after successful lobby creation.

Payload:

{
  "lobbyId": "AB12CD",
  "lobbyName": "Friday Room",
  "adminId": "session-id",
  "maxUsers": 6,
  "isPrivate": false,
  "createdAt": "2026-04-22T10:00:00.000Z",
  "currentUsers": [
    {
      "sessionId": "session-id",
      "displayName": "Curious Tiger",
      "isAdmin": true
    }
  ],
  "pendingJoinRequests": []
}
  1. lobby:publicListUpdated
  • Broadcast when public lobby list changes.

Payload:

[
  {
    "lobbyId": "AB12CD",
    "lobbyName": "Friday Room",
    "currentUsers": 2,
    "maxUsers": 6,
    "status": "open",
    "createdAt": "2026-04-22T10:00:00.000Z"
  }
]
  1. lobby:joinRequestSent
  • Sent to lobby admin when someone requests to join.

Payload:

{
  "lobbyId": "AB12CD",
  "request": {
    "requestId": "f9d9f890-1c6f-4efe-a730-ec8bdafd01cc",
    "lobbyId": "AB12CD",
    "sessionId": "requester-session-id",
    "chosenName": "Blue Falcon",
    "createdAt": "2026-04-22T10:01:10.000Z",
    "createdAtMs": 1713780070000
  }
}
  1. lobby:joinRequestResolved
  • Sent to requester when admin accepts/rejects.

Accepted payload:

{
  "status": "accepted",
  "lobby": {
    "lobbyId": "AB12CD",
    "lobbyName": "Friday Room",
    "adminId": "admin-session-id",
    "maxUsers": 6,
    "isPrivate": false,
    "createdAt": "2026-04-22T10:00:00.000Z",
    "currentUsers": [],
    "pendingJoinRequests": []
  },
  "session": {
    "sessionId": "requester-session-id",
    "displayName": "Blue Falcon",
    "lobbyId": "AB12CD"
  }
}

Rejected payload:

{
  "status": "rejected",
  "lobbyId": "AB12CD",
  "requestId": "f9d9f890-1c6f-4efe-a730-ec8bdafd01cc"
}
  1. lobby:userJoined
  • Broadcast to users in lobby when a user is approved and joins.

Payload:

{
  "lobbyId": "AB12CD",
  "user": {
    "sessionId": "requester-session-id",
    "displayName": "Blue Falcon"
  },
  "currentUsers": []
}
  1. lobby:userLeft
  • Broadcast when user leaves, gets kicked, or cleanup removes user.

Payload:

{
  "lobbyId": "AB12CD",
  "user": {
    "sessionId": "user-session-id",
    "displayName": "Blue Falcon"
  },
  "reason": "left",
  "currentUsers": []
}
  1. lobby:userKicked
  • Sent directly to kicked user.

Payload:

{
  "lobbyId": "AB12CD",
  "reason": "kicked"
}
  1. lobby:userMuted
  • Broadcast when admin mutes or unmutes a user.

Payload:

{
  "lobbyId": "AB12CD",
  "targetSessionId": "user-session-id",
  "muted": true
}
  1. chat:messageReceived
  • Broadcast to lobby when message is sent by approved and unmuted user.

Payload:

{
  "senderName": "Blue Falcon",
  "senderSessionId": "user-session-id",
  "messageContent": "Hello everyone",
  "timestamp": "2026-04-22T10:02:00.000Z"
}
Client -> Server (with Ack)
  1. lobby:listPublic
  • Request public lobbies via socket.

Request payload:

{}

Success ack payload:

{
  "success": true,
  "lobbies": []
}
  1. lobby:create
  • Create lobby. Creator becomes admin and joins immediately.

Request payload:

{
  "lobbyName": "Friday Room",
  "adminName": "Curious Tiger",
  "maxUsers": 6,
  "isPrivate": false
}

Success ack payload:

{
  "success": true,
  "lobby": {},
  "session": {
    "sessionId": "admin-session-id",
    "displayName": "Curious Tiger",
    "lobbyId": "AB12CD"
  }
}
  1. lobby:joinRequest
  • Send join request to lobby.

Request payload:

{
  "lobbyId": "AB12CD",
  "chosenName": "Blue Falcon"
}

Success ack payload:

{
  "success": true,
  "request": {
    "requestId": "f9d9f890-1c6f-4efe-a730-ec8bdafd01cc",
    "lobbyId": "AB12CD",
    "sessionId": "requester-session-id",
    "chosenName": "Blue Falcon",
    "createdAt": "2026-04-22T10:01:10.000Z",
    "createdAtMs": 1713780070000
  }
}
  1. lobby:joinRequest:respond
  • Admin accepts or rejects pending request.

Request payload:

{
  "lobbyId": "AB12CD",
  "requestId": "f9d9f890-1c6f-4efe-a730-ec8bdafd01cc",
  "action": "accept"
}

Success ack payload:

{
  "success": true,
  "status": "accepted"
}
  1. chat:sendMessage
  • Send message to current lobby.

Request payload:

{
  "lobbyId": "AB12CD",
  "messageContent": "Hello everyone"
}

Success ack payload:

{
  "success": true,
  "message": {
    "senderName": "Blue Falcon",
    "senderSessionId": "user-session-id",
    "messageContent": "Hello everyone",
    "timestamp": "2026-04-22T10:02:00.000Z"
  }
}
  1. lobby:kick
  • Admin removes a user from lobby.

Request payload:

{
  "lobbyId": "AB12CD",
  "targetSessionId": "user-session-id"
}

Success ack payload:

{
  "success": true
}
  1. lobby:mute
  • Admin mutes/unmutes a user.

Request payload:

{
  "lobbyId": "AB12CD",
  "targetSessionId": "user-session-id",
  "muted": true
}

Success ack payload:

{
  "success": true
}

Validation and Rules for Frontend

  • maxUsers hard limit is 6.
  • Display name max length is 20.
  • Display names allow only letters, numbers, and spaces.
  • Duplicate names in same lobby are auto-suffixed (_2, _3, ...).
  • Only approved users can send chat messages.
  • Muted users cannot send chat messages.
  • Join requests and lobby creation are rate-limited per temporary session.
  • Lobby IDs are uppercase alphanumeric 6-character strings.
  • Lobbies are cleaned up when empty or inactive for too long.
  • Pending requests are cleaned up when stale.

Text Content Management

1. Create Content

POST /get-it/text-content

Request Body:

{
  "contentname": "My Content",     // Required, max 50 chars
  "description": "Description",    // Optional, max 500 chars  
  "content": "The actual content"  // Required, no limit
}

Response:

{
  "success": true,
  "ui": "a1b2c3",                 // 6-char unique pin
  "message": "Content created successfully"
}

2. Get Content

GET /get-it/text-content/:ui

Response:

{
  "success": true,
  "data": {
    "ui": "a1b2c3",
    "contentname": "My Content",
    "description": "Description",
    "content": "The actual content",
    "createdAt": "2023-01-01T00:00:00.000Z",
    "updatedAt": "2023-01-01T00:00:00.000Z"
  }
}

File Upload & Management

3. Upload Files

POST /get-it/files

Upload up to 10 files and receive a unique 6-character key for retrieval. You can also add more files to an existing key/lobby.

Request:

  • Content-Type: multipart/form-data
  • Field name: files (array of files)
  • Field name: names (optional, JSON array of custom names)
  • Field name: key (optional, existing key to add files to)
  • Maximum: 10 files per lobby
  • Max file size: 15MB per file

Postman Setup (New Upload):

  1. Set method to POST and URL to http://localhost:3000/get-it/files
  2. Go to "Body" tab β†’ select "form-data"
  3. Add key files with type File (you can add multiple files with the same key)
  4. Optionally add key names with type Text and value: ["Custom Name 1", "Custom Name 2"]

Postman Setup (Add to Existing Lobby):

  1. Same as above, but also add key key with type Text and value: abc123 (your existing key)
  2. System will check if lobby has space and add files accordingly

JavaScript Fetch Example (Create New Lobby):

const formData = new FormData();
formData.append('files', fileInput1.files[0]);
formData.append('files', fileInput2.files[0]);
formData.append('names', JSON.stringify(['My Document', 'My Image']));

fetch('http://localhost:3000/get-it/files', {
  method: 'POST',
  body: formData
})
.then(response => response.json())
.then(data => console.log(data));

JavaScript Fetch Example (Add to Existing Lobby):

const formData = new FormData();
formData.append('files', fileInput3.files[0]);
formData.append('key', 'abc123'); // Existing key

fetch('http://localhost:3000/get-it/files', {
  method: 'POST',
  body: formData
})
.then(response => response.json())
.then(data => console.log(data));

Response (New Lobby):

{
  "success": true,
  "key": "xY9aB3",
  "filesUploaded": 2,
  "totalFiles": 2,
  "message": "Files uploaded successfully"
}

Response (Added to Existing Lobby):

{
  "success": true,
  "key": "xY9aB3",
  "filesUploaded": 1,
  "totalFiles": 3,
  "message": "Successfully added 1 file(s) to the lobby"
}

Error Response (Lobby Full):

{
  "success": false,
  "message": "This lobby is full (10/10 files). Cannot add more files.",
  "currentFiles": 10,
  "maxFiles": 10
}

Error Response (Not Enough Space):

{
  "success": false,
  "message": "This lobby can only accept 2 more file(s). You tried to upload 5 file(s).",
  "currentFiles": 8,
  "slotsAvailable": 2,
  "maxFiles": 10
}

4. Get Files Information

GET /get-it/files/:key

Retrieve information about all files associated with a key.

Response:

{
  "success": true,
  "key": "xY9aB3",
  "totalFiles": 3,
  "files": [
    {
      "name": "My Important Document",
      "originalName": "document.pdf",
      "mimetype": "application/pdf",
      "size": 2048576,
      "downloadUrl": "/get-it/files/download/xY9aB3/1733567890123-document.pdf"
    },
    {
      "name": "Profile Picture",
      "originalName": "image.jpg",
      "mimetype": "image/jpeg",
      "size": 1024000,
      "downloadUrl": "/get-it/files/download/xY9aB3/1733567890124-image.jpg"
    }
  ],
  "createdAt": "2025-12-07T10:30:00.000Z",
  "updatedAt": "2025-12-07T10:30:00.000Z"
}

5. Download File

GET /get-it/files/download/:key/:filename

Download a specific file using its key and filename.

Postman:

  • Method: GET
  • URL: http://localhost:3000/get-it/files/download/xY9aB3/1733567890123-document.pdf

JavaScript Fetch:

fetch('http://localhost:3000/get-it/files/download/xY9aB3/1733567890123-document.pdf')
  .then(response => response.blob())
  .then(blob => {
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'document.pdf';
    a.click();
  });

Returns the file with appropriate headers for download.

Installation

  1. Install dependencies:
npm install
  1. Set up Supabase:

    • Create a project at supabase.com
    • Create a storage bucket named get-it-files
    • Make the bucket public (for file downloads)
    • Copy your project URL and anon key
  2. Configure environment variables in .env:

PORT=3000
MONGODB_URI=mongodb://localhost:27017/contentdb
NODE_ENV=production

# Supabase Configuration
SUPABASE_URL=your_supabase_project_url
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_BUCKET_NAME=get-it-files
  1. Start the server:
npm start

For development with auto-restart:

npm run dev

Project Structure

β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   β”œβ”€β”€ Content.js          # Text content schema
β”‚   β”‚   └── FileUpload.js       # File upload schema
β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”œβ”€β”€ contentController.js # Content business logic
β”‚   β”‚   └── fileController.js    # File handling logic
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ contentRoutes.js    # Content API routes
β”‚   β”‚   └── fileRoutes.js       # File API routes
β”‚   β”œβ”€β”€ helpers/
β”‚   β”‚   β”œβ”€β”€ supabase.js         # Supabase client setup
β”‚   β”‚   └── fileStorage.js      # Supabase storage helpers
β”‚   └── server.js               # Main application
β”œβ”€β”€ uploads/                    # Temporary file storage (auto-cleaned)
β”œβ”€β”€ package.json
β”œβ”€β”€ .env                        # Environment variables
β”œβ”€β”€ .gitignore
└── README.md

Security Features

  • Helmet: Security headers for Express apps
  • CORS: Configurable cross-origin resource sharing
  • Rate Limiting: 100 requests per 15 minutes per IP
  • Input Validation: Server-side validation for all text and file inputs
  • File Size Limits: 100MB maximum per file, 10 files maximum per upload
  • Error Handling: Comprehensive error handling without sensitive data leaks
  • Automatic Cleanup: Failed uploads are automatically cleaned up

Dependencies

  • express: Web framework
  • mongoose: MongoDB ODM
  • multer: File upload handling
  • @supabase/supabase-js: Supabase client for cloud storage
  • cors: CORS middleware
  • helmet: Security middleware
  • express-rate-limit: Rate limiting
  • express-validator: Input validation
  • dotenv: Environment variables

API Response Format

All endpoints follow a consistent response format:

Success Response:

{
  "success": true,
  "data": { /* response data */ },
  "message": "Operation completed successfully"
}

Error Response:

{
  "success": false,
  "message": "Error description",
  "errors": [ /* validation errors if applicable */ ]
}

File Upload Notes

  • Files are temporarily stored locally via multer, then uploaded to Supabase Storage
  • Each file gets a unique timestamp-based filename in Supabase
  • Original filenames and custom names are preserved in MongoDB
  • Public URLs are generated for easy file access
  • Files are stored in the Supabase bucket specified in environment variables
  • All file metadata is stored in MongoDB for easy retrieval

License

MIT

  • express: Web framework
  • mongoose: MongoDB ODM
  • cors: CORS middleware
  • helmet: Security middleware
  • express-rate-limit: Rate limiting
  • express-validator: Input validation
  • dotenv: Environment variables

About

πŸš€ Content Management Backend : A production-ready REST API for managing text content and file uploads using Express.js and MongoDB.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages