Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FileBud Backend

FileBud is an Express, MongoDB, and Cloudinary backend for a cloud storage application with authenticated file and folder management. It models user storage as a hierarchical directory tree, stores file metadata in MongoDB, stores binary assets in Cloudinary, and coordinates uploads, downloads, signed media access, recursive deletion, and per-user quota accounting.

Status: The backend MVP implements its current file-management scope. Production hardening, automated testing, and operational cleanup tooling remain in progress.

Live Demo

Highlights

  • JWT authentication with HTTP-only cookie and bearer-token support
  • Automatic root-folder provisioning during registration
  • User-scoped file and folder ownership checks
  • Nested folder hierarchy with parent and child references
  • Recursive folder deletion with nested storage accounting
  • Per-user storage usage tracking and a default 1 GiB quota
  • Authenticated Cloudinary uploads with metadata persisted in MongoDB
  • Signed Cloudinary URLs for access, download, thumbnails, and HLS video delivery
  • MongoDB transactions for multi-document write workflows
  • Compensating cleanup after partial upload failures
  • Filename conflict handling within a folder
  • Basic liveness endpoint for hosted deployments

Features

Authentication

  • Register users with email, full name, and password
  • Hash passwords with bcrypt before persistence
  • Create a root folder as part of account registration
  • Issue access and refresh JWTs on login
  • Accept access tokens from cookies or Authorization: Bearer <token>
  • Remove the stored refresh token and clear cookies on logout

Files

  • Upload one multipart file at a time through Multer
  • Temporarily write uploads to public/temp
  • Resolve duplicate names within a folder using numeric suffixes
  • Persist Cloudinary public_id, resource type, format, byte size, and optional duration
  • Return signed access and attachment-download URLs
  • Redirect supported thumbnail requests to signed transformed Cloudinary URLs
  • Delete file metadata, folder references, quota usage, and Cloudinary assets

Folders

  • Create nested folders below an owned parent folder
  • Resolve duplicate child-folder titles using numeric suffixes
  • Fetch a folder with its direct files and subfolders populated
  • Delete nested folders recursively
  • Protect each user's root folder from deletion

Storage Quota

  • Store storageUsed and maxStorage on each user
  • Default each account to 1073741824 bytes (1 GiB)
  • Reject uploads that exceed the currently available quota
  • Increment usage after successful uploads
  • Decrement usage during file and recursive folder deletion

Cloudinary / Media Delivery

  • Store uploaded assets as authenticated Cloudinary resources
  • Request asynchronous eager HLS generation for video uploads
  • Return signed HLS (m3u8) URLs for video streaming
  • Generate signed JPG thumbnails for supported images and videos
  • Group recursive remote deletions by Cloudinary resource type

Security and Reliability

  • Verify resource ownership before file and folder operations
  • Use MongoDB transactions for registration, folder creation, upload metadata updates, and deletions
  • Remove temporary files after upload processing
  • Attempt Cloudinary cleanup if a database step fails after remote upload
  • Log failed Cloudinary deletions for later handling
  • Limit JSON and URL-encoded request bodies to 16 KB
  • Limit individual uploads to 100 MB

Tech Stack

Area Technology
Runtime Node.js with ECMAScript modules
API framework Express 4
Database MongoDB
ODM and transactions Mongoose 7
File storage and delivery Cloudinary
Authentication JSON Web Tokens (jsonwebtoken)
Password hashing bcrypt
Multipart uploads Multer
Cookies cookie-parser
Cross-origin access cors
Environment configuration dotenv
Development runner Nodemon

Architecture

The implementation keeps orchestration in controllers. There is currently no separate service layer.

Client
  -> Express app and middleware
  -> /api/v1 routes
  -> optional JWT verification
  -> controllers
  -> Mongoose models and Cloudinary utilities
  -> MongoDB and Cloudinary

Upload Flow

Authenticated upload
  -> Multer temporary file
  -> quota and folder-ownership checks
  -> authenticated Cloudinary upload
  -> MongoDB transaction:
       create File metadata
       update Folder.files
       increment User.storageUsed
  -> remove temporary file

Delete Flow

Authenticated delete
  -> ownership and permission checks
  -> MongoDB transaction:
       remove metadata and parent references
       decrement User.storageUsed
  -> commit database transaction
  -> attempt Cloudinary deletion
  -> log failed remote deletions

Cloudinary calls cannot participate in MongoDB transactions. The backend uses cleanup attempts and a local deletion log to reduce cross-system inconsistency, but it does not yet include an automated retry worker.

Project Structure

.
|-- .env.sample                         Example environment variables
|-- package.json                        Dependencies and npm scripts
|-- public/
|   `-- temp/                            Temporary Multer uploads
`-- src/
    |-- app.js                          Express middleware and route mounting
    |-- constants.js                    Shared database name
    |-- index.js                        Database connection and HTTP startup
    |-- controllers/
    |   |-- file.controller.js          Upload, delivery, streaming, and deletion
    |   |-- folder.controller.js        Folder fetch, create, and recursive deletion
    |   `-- user.controller.js          Registration, login, logout, and current user
    |-- db/
    |   `-- index.js                    MongoDB connection helper
    |-- middlewares/
    |   |-- auth.middleware.js          JWT verification and user loading
    |   `-- multer.middleware.js        Temporary storage and upload-size limit
    |-- models/
    |   |-- file.model.js               Cloudinary-backed file metadata
    |   |-- folder.model.js             Directory-tree metadata
    |   `-- user.model.js               Account, token, and quota metadata
    |-- routes/                          Express route definitions
    `-- utils/                           API response, error, async, and Cloudinary helpers

API Overview

All routes use the /api/v1 prefix.

Area Method Route Purpose
Users POST /api/v1/users/register Register a user and create a root folder
Users POST /api/v1/users/login Validate credentials and issue tokens
Users POST /api/v1/users/logout Clear stored refresh token and cookies
Users GET /api/v1/users/getUser Return the authenticated user
Folders POST /api/v1/folders/create Create a child folder
Folders GET /api/v1/folders/fetch/:folderId Fetch direct folder contents
Folders DELETE /api/v1/folders/delete Delete a folder recursively
Files POST /api/v1/files/upload Upload multipart field file into body folderId
Files GET /api/v1/files/fetch?fileId=... Return a signed file-access URL
Files GET /api/v1/files/download?fileId=... Return a signed attachment-download URL
Files DELETE /api/v1/files/delete Delete the body fileId
Files GET /api/v1/files/thumbnail/:id Redirect to a signed thumbnail URL
Files GET /api/v1/files/stream?fileId=... Return a signed HLS URL for a video
Operations GET /api/v1/files/awake Return a basic liveness response

Except for registration, login, and /files/awake, routes require a valid access token.

Database Design

User

Stores account details, password hash, latest refresh token, root-folder reference, quota state, and an access-limitation flag. email is unique and indexed. storageUsed defaults to 0; maxStorage defaults to 1 GiB.

Folder

Represents a directory node. Each folder stores its owner, parent-folder reference, direct child-folder references, and direct file references. A root folder has no parent.

File

Stores Cloudinary-backed asset metadata: publicId, display title, owner, parent folder, byte size, resource type, optional format, optional duration, and optional URL-expiry metadata.

Files and folders carry owner references so controllers can enforce user scoping before access or mutation. The current implementation does not include soft-delete or archive behavior.

Key Backend Design Decisions

  • Store binary assets in Cloudinary while keeping ownership, hierarchy, and file metadata in MongoDB.
  • Represent folders with both parent references and direct child arrays for directory-style navigation.
  • Provision a root folder during registration within the same MongoDB transaction as user creation.
  • Maintain User.storageUsed as derived account state and update it during upload and deletion flows.
  • Check ownership in controllers before returning or modifying files and folders.
  • Resolve duplicate file and folder names locally within their parent folder.
  • Upload to Cloudinary before starting the metadata transaction to avoid holding a database transaction open during remote transfer.
  • Use compensating Cloudinary deletion when an upload succeeds remotely but later database work fails.
  • Commit metadata deletion before attempting remote Cloudinary cleanup, then log failed remote deletions.
  • Use authenticated Cloudinary resources and signed delivery URLs instead of exposing public asset URLs.

Local Development

Prerequisites

  • Node.js and npm
  • A transaction-capable MongoDB deployment, such as a replica set
  • A Cloudinary account

Setup

git clone <your-repository-url>
cd file-bud-backend
npm install

Create a .env file from .env.sample, fill in the required values, then run:

npm run dev

The API defaults to http://localhost:8000. The server appends /filebud to MONGODB_URI.

public/temp is already included for temporary uploads. The application also expects a writable logs/ directory when recording failed Cloudinary deletions, but it does not currently create that directory automatically.

Environment Variables

Variable Purpose
PORT HTTP port; defaults to 8000
CORS_ORIGIN Allowed frontend origin for credentialed requests
MONGODB_URI MongoDB base URI; /filebud is appended by the code
ACCESS_TOKEN_SECRET Access-token signing and verification secret
ACCESS_TOKEN_EXPIRY Access-token lifetime
REFRESH_TOKEN_SECRET Refresh-token signing secret
REFRESH_TOKEN_EXPIRY Refresh-token lifetime
CLOUDINARY_CLOUD_NAME Cloudinary cloud name
CLOUDINARY_API_KEY Cloudinary API key
CLOUDINARY_API_SECRET Cloudinary API secret

Useful Commands

Command Purpose
npm run dev Run the API with Nodemon and dotenv preloading

The repository does not currently define production start, test, lint, or build scripts.

Production Notes

  • Use a MongoDB replica set or sharded cluster because core workflows use transactions.
  • Store JWT and Cloudinary credentials as deployment secrets.
  • Set CORS_ORIGIN to the deployed frontend origin.
  • Add a production start script and configure the chosen hosting platform or process manager.
  • Ensure temporary uploads use writable storage appropriate for the hosting platform.
  • Create a durable cleanup strategy for failed Cloudinary deletions; local logs are insufficient on ephemeral hosts.
  • Add structured logs, monitoring, readiness checks, and alerting.
  • Review console logging before deployment because controllers currently print request and asset details.
  • Keep .env files out of version control.

Current Scope and Limitations

  • No automated test suite is included.
  • No rename, move, sharing, search, admin, or bulk-operation endpoints are present.
  • No background worker or scheduled cleanup job processes failed Cloudinary deletions.
  • No virus scanning, resumable upload, or chunked upload support is present.
  • No rate limiting, Helmet middleware, CSRF protection, audit logging, or observability stack is included.
  • Quota checks can race during concurrent uploads because they are not enforced with an atomic conditional update.
  • Temporary uploads use original filenames under the statically served public directory.
  • The expected logs/ directory is not created automatically.
  • Cloudinary storage is integrated directly; there is no storage-provider abstraction.

License

This repository uses the ISC license. The project is developed for educational and portfolio purposes.