A secure, scalable file storage backend built with Express and TypeScript. Supports chunked file uploads, user authentication, and file management operations.
- ✅ User Authentication - Secure authentication using Better-Auth
- ✅ Chunked File Uploads - Support for large file uploads with resumable chunks
- ✅ File Management - Upload, download, view, and delete files
- ✅ Stream-based Downloads - Memory-efficient file streaming
- ✅ SQLite Database - Lightweight database with Drizzle ORM
- ✅ Type Safety - Full TypeScript coverage with strict mode
- ✅ Input Validation - Zod schema validation for all endpoints
- Runtime: Node.js 20+
- Framework: Express 4
- Language: TypeScript 5
- Database: SQLite with Better-SQLite3
- ORM: Drizzle ORM
- Authentication: Better-Auth
- Validation: Zod
- File Handling: Express-Fileupload
- Node.js >= 20.x
- npm or yarn
-
Clone the repository
git clone <repository-url> cd cloud_box/backend
-
Install dependencies
npm install
-
Set up environment variables
Create a
.envfile in the backend directory using the template.env.example:# Server Configuration PORT=3000 NODE_ENV=development # Better-Auth Configuration BETTER_AUTH_SECRET=<any-simple-string> BETTER_AUTH_URL=http://localhost:3000 # CORS Configuration FRONTEND_URL=http://localhost:5173 # File Storage Configuration CHUNK_SIZE=5242880 # Pagination RETRIEVAL_LIMIT=10
-
Initialize the database
npm run db:push
npm run devServer runs on http://localhost:3000 with hot reload enabled.
npm run build
npm start# Open Drizzle Studio (visual database editor)
npm run db:studio
# Push schema changes to database
npm run db:pushbackend/
├── src/
│ ├── config/ # Environment configuration
│ ├── database/ # Database setup and schemas
│ │ ├── schemas/ # Drizzle table schemas
│ │ └── setup.ts # Database connection
│ ├── lib/ # Shared utilities
│ │ ├── auth.ts # Better-auth setup
│ │ └── utils.ts # Helper functions
│ ├── middleware/ # Express middleware
│ ├── models/ # TypeScript interfaces/types
│ ├── repositories/ # Database access layer
│ │ ├── interfaces.ts # Repository contracts
│ │ ├── file.repository.ts
│ │ └── upload.repository.ts
│ ├── routes/ # API route handlers
│ │ ├── auth.ts # Authentication routes
│ │ └── file.ts # File operation routes
│ ├── services/ # Business logic layer
│ │ ├── file.service.ts
│ │ └── storage.service.ts
│ ├── validators/ # Zod validation schemas
│ └── index.ts # Application entry point
├── uploads/ # File storage (gitignored)
├── chunks/ # Temporary chunk storage (gitignored)
├── .env # Environment variables (gitignored)
└── package.json
All file endpoints require authentication via session cookies.
POST /api/auth/sign-up- Register new userPOST /api/auth/sign-in- LoginPOST /api/auth/sign-out- LogoutGET /api/auth/session- Get current session
GET /api/files/list?limit=10&offset=0&sortBy=createdAt&sortOrder=descQuery Parameters:
limit(optional): Number of files to return (default: 10)offset(optional): Pagination offset (default: 0)sortBy(optional): Sort field -name,size,createdAt(default:createdAt)sortOrder(optional): Sort order -asc,desc(default:desc)
1. Initiate Upload
POST /api/files/upload/initiate
Content-Type: application/json
{
"data": {
"name": "document.pdf",
"size": 1048576,
"type": "application/pdf",
"mimeType": "application/pdf"
}
}2. Upload Chunk
POST /api/files/upload/part
Content-Type: multipart/form-data
data: {"uploadId": "uuid", "index": 0}
chunk: <binary-data>3. Complete Upload
POST /api/files/upload/complete
Content-Type: application/json
{
"data": {
"uploadId": "uuid"
}
}4. Abort Upload (Optional)
POST /api/files/upload/abort
Content-Type: application/json
{
"data": {
"uploadId": "uuid"
}
}GET /api/files/download/:fileIdDownloads file with Content-Disposition: attachment
GET /api/files/view/:fileIdStreams file for inline viewing (images, videos, PDFs)
DELETE /api/files/:fileIdRoutes → Services → Repositories → Database
↓ ↓ ↓
Validators Storage Drizzle ORM
Routes: Handle HTTP requests, validation, and responses Services: Business logic and orchestration Repositories: Data access layer (abstraction over Drizzle) Storage Service: File system operations (local/S3-ready)
- Repository Pattern: Abstracts database access
- Service Layer: Separates business logic from HTTP concerns
- Dependency Injection: Services receive dependencies via constructor
| Variable | Description | Default | Required |
|---|---|---|---|
PORT |
Server port | 3000 |
No |
NODE_ENV |
Environment | development |
No |
BETTER_AUTH_SECRET |
Secret for JWT signing | - | Yes |
BETTER_AUTH_URL |
Auth callback URL | - | Yes |
FRONTEND_URL |
CORS origin | - | Yes |
CHUNK_SIZE |
Upload chunk size limit | 5MB |
No |
RETRIEVAL_LIMIT |
Default pagination limit | 10 |
No |
-
Build the application
npm run build
-
Set production environment variables
NODE_ENV=production BETTER_AUTH_SECRET=<strong-secret> BETTER_AUTH_URL=https://your-domain.com
-
Run the production server
npm start
- Use a process manager (PM2, systemd)
- Configure reverse proxy (nginx, Apache)
- Enable HTTPS with SSL certificates
- Use PostgreSQL/MySQL instead of SQLite for scalability
- Migrate to S3 for file storage (StorageService is designed for easy swap)
- Add rate limiting and DDoS protection
- Enable logging and monitoring
- Add maximum storage quota for users based on tiers