A production-level backend API for content and file management using Express.js and MongoDB.
- 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
The backend now supports realtime anonymous lobby chat using Socket.IO.
Base URL (local):
- REST: http://localhost:3000
- Socket.IO: http://localhost:3000
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"
}
]
}- Connect socket to server.
- Server emits
session:createdwith a temporarysessionId. - 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"
}Event names are case-sensitive.
session:created
- Sent after socket connects.
Payload:
{
"sessionId": "2e10c5a9-0ec7-45e6-8e0a-b8dbe09efcb5",
"message": "Temporary anonymous session created"
}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": []
}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"
}
]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
}
}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"
}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": []
}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": []
}lobby:userKicked
- Sent directly to kicked user.
Payload:
{
"lobbyId": "AB12CD",
"reason": "kicked"
}lobby:userMuted
- Broadcast when admin mutes or unmutes a user.
Payload:
{
"lobbyId": "AB12CD",
"targetSessionId": "user-session-id",
"muted": true
}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"
}lobby:listPublic
- Request public lobbies via socket.
Request payload:
{}Success ack payload:
{
"success": true,
"lobbies": []
}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"
}
}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
}
}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"
}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"
}
}lobby:kick
- Admin removes a user from lobby.
Request payload:
{
"lobbyId": "AB12CD",
"targetSessionId": "user-session-id"
}Success ack payload:
{
"success": true
}lobby:mute
- Admin mutes/unmutes a user.
Request payload:
{
"lobbyId": "AB12CD",
"targetSessionId": "user-session-id",
"muted": true
}Success ack payload:
{
"success": true
}maxUsershard 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.
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"
}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"
}
}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):
- Set method to
POSTand URL tohttp://localhost:3000/get-it/files - Go to "Body" tab β select "form-data"
- Add key
fileswith typeFile(you can add multiple files with the same key) - Optionally add key
nameswith typeTextand value:["Custom Name 1", "Custom Name 2"]
Postman Setup (Add to Existing Lobby):
- Same as above, but also add key
keywith typeTextand value:abc123(your existing key) - 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
}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"
}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.
- Install dependencies:
npm install-
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
-
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
- Start the server:
npm startFor development with auto-restart:
npm run devβββ 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
- 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
- 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
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 */ ]
}- 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
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