Lania Storage Service
File storage service yang berfungsi sebagai middleman untuk service lain (upload) atau frontend (upload, read, download) untuk integrasi dan olah file ke object storage (S3-compatible).
Features
- ✅ File Upload - Upload file dengan validasi tipe dan ukuran
- ✅ File Read - Baca file untuk ditampilkan inline (untuk gambar, dll)
- ✅ File Download - Download file sebagai attachment
- ✅ PDF Reader - Endpoint khusus untuk membaca PDF dengan proper headers
- ✅ File Delete - Soft delete file dari storage dan database
- ✅ Object Storage Integration - Support S3-compatible storage (AWS S3, Supabase Storage, dll)
- ✅ Local Storage Fallback - Otomatis fallback ke local storage jika object storage tidak dikonfigurasi
- ✅ Image Compression - Otomatis compress gambar (PNG, JPG, JPEG) menggunakan Sharp
- ✅ Database Integration - Menggunakan Prisma untuk menyimpan metadata file
- ✅ Swagger Documentation - API documentation tersedia di
/api-docs - ✅ CORS Support - Support untuk frontend integration
- ✅ Health Check - Endpoint
/healthuntuk monitoring
Tech Stack
- Runtime: Node.js dengan Express.js
- Database: PostgreSQL dengan Prisma ORM
- Object Storage: AWS S3 SDK (support S3-compatible storage)
- Image Processing: Sharp
- File Upload: Multer
- Logging: Winston dengan daily rotation
- Documentation: Swagger/OpenAPI
Prerequisites
- Node.js (v18 atau lebih baru)
- PostgreSQL database (menggunakan schema dari
lania_common) - (Optional) S3-compatible object storage (AWS S3, Supabase Storage, dll)
Installation
- Clone repository dan install dependencies:
npm install
- Setup environment variables:
Copy .env.example ke .env dan isi dengan konfigurasi yang sesuai:
# Server Configuration
PORT=8090
NODE_ENV=development
# File Storage
FILES_DIRECTORY=./files
# Database (PostgreSQL)
DATABASE_URL=postgresql://user:password@localhost:5432/lania_common
# Object Storage (S3-compatible) - Optional
# Jika tidak dikonfigurasi, akan menggunakan local storage
AWS_S3_BUCKET_NAME=lanya-bucket
AWS_S3_REGION=ap-southeast-1
AWS_S3_ENDPOINT=https://your-storage-endpoint.com/storage/v1/s3
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
# CORS Configuration
CORS_ORIGIN=* # Set specific origin in production, e.g., http://localhost:3000
# Logging
LOG_LEVEL=debug
- Generate Prisma Client:
npx prisma generate
- Pastikan database schema sudah ada (table
file_uploadsdi databaselania_common)
Running the Application
Development Mode
npm run dev
Server akan berjalan di http://localhost:8090 (atau port yang dikonfigurasi di .env)
Production Mode
npm run build
npm start
API Endpoints
Health Check
GET /health
Response:
{
"status": "ok",
"timestamp": "2025-01-15T10:30:00.000Z",
"service": "lania-storage",
"version": "1.0.0"
}
Upload File
POST /api/files
Content-Type: multipart/form-data
Form Data:
file(required): File yang akan diuploadtenant_id(optional): UUID tenant IDuser_id(optional): UUID user IDis_public(optional): Boolean, defaultfalse
Supported File Types:
- Images: PNG, JPG, JPEG
- Documents: PDF, DOC, DOCX, XLS, XLSX, CSV
File Size Limit: 5MB (default, bisa dikonfigurasi via FILE_SIZE_LIMIT_MB)
Response:
{
"message": "File uploaded successfully",
"data": {
"id": "uuid",
"file_name": "original-filename.pdf",
"file_path": "data-tenant/{tenant-id}/1234567890-123456789.pdf",
"file_type": "pdf",
"file_size": 1024000,
"mime_type": "application/pdf",
"description": null,
"is_public": false,
"created_at": "2025-01-15T10:30:00.000Z",
"updated_at": "2025-01-15T10:30:00.000Z"
}
}
Read File (Inline Display)
GET /api/read/{path}
Mengembalikan file untuk ditampilkan inline di browser (cocok untuk gambar, PDF viewer, dll).
Example:
GET /api/read/data-tenant/123/1234567890-123456789.pdf
Download File
GET /api/download/{path}
Mengembalikan file sebagai download attachment.
Example:
GET /api/download/data-tenant/123/1234567890-123456789.pdf
Read PDF (PDF Viewer)
GET /api/pdf/{path}
Endpoint khusus untuk membaca PDF dengan headers yang optimal untuk PDF viewer di browser.
Example:
GET /api/pdf/data-tenant/123/1234567890-123456789.pdf
Delete File
DELETE /api/files/{path}
Soft delete file dari storage dan database.
Response:
{
"message": "File deleted successfully"
}
Object Storage Structure
File yang diupload ke object storage akan disimpan dengan struktur:
data-tenant/{tenant-id}/{unique-filename}
Jika tenant_id tidak disediakan, akan menggunakan folder data-tenant/default/.
Local Storage vs Object Storage
Service ini mendukung dua mode storage:
-
Object Storage Mode (Recommended untuk production)
- File disimpan di S3-compatible storage
- Otomatis digunakan jika AWS credentials dikonfigurasi
- File path format:
data-tenant/{tenant-id}/{filename}
-
Local Storage Mode (Fallback)
- File disimpan di local filesystem
- Digunakan jika object storage tidak dikonfigurasi
- File path format: relative path dari
FILES_DIRECTORY
Image Compression
File gambar (PNG, JPG, JPEG) akan otomatis di-compress menggunakan Sharp dengan quality 80% untuk menghemat storage space.
Database Schema
Service ini menggunakan table file_uploads dari database lania_common:
CREATE TABLE file_uploads (
id CHAR(36) PRIMARY KEY,
tenant_id CHAR(36),
user_id CHAR(36),
file_name VARCHAR(255),
file_path VARCHAR(2048),
file_type VARCHAR(100),
file_size BIGINT,
mime_type VARCHAR(255),
description TEXT,
is_public BOOLEAN DEFAULT false,
created_at TIMESTAMP,
updated_at TIMESTAMP,
deleted_at TIMESTAMP
);
Security Notes
⚠️ Authorization: Saat ini authorization check untuk file access masih dalam TODO. Untuk production, disarankan untuk:
- Menambahkan authentication middleware (JWT, dll)
- Validasi
tenant_iddanuser_iduntuk memastikan user hanya bisa mengakses file mereka sendiri - Validasi
is_publicflag untuk file yang bisa diakses publik
API Documentation
Swagger documentation tersedia di:
http://localhost:8090/api-docs
Logging
Logs disimpan di folder logs/ dengan daily rotation:
{DATE}-error.log: Hanya error logs{DATE}-combined.log: Semua logs
Log retention: 14 hari (otomatis dihapus setelah 2 minggu)
Error Handling
Service menggunakan centralized error handling dengan logging ke Winston. Error response format:
{
"message": "Error message",
"status": 500
}
Development
Project Structure
lania-storage/
├── src/
│ ├── common/
│ │ ├── logger/ # Winston logger configuration
│ │ └── middleware/ # Express middleware
│ ├── config/ # Configuration files
│ ├── controllers/ # Request handlers
│ ├── prisma/ # Prisma client setup
│ ├── routes.ts # Route definitions
│ ├── server.ts # Express app setup
│ └── services/ # Business logic
├── prisma/
│ └── schema.prisma # Prisma schema
└── files/ # Local storage directory
Scripts
npm run dev: Run development server dengan nodemonnpm run build: Build TypeScript ke JavaScriptnpm start: Run production server
Integration Examples
Frontend (React/Next.js)
// Upload file
const formData = new FormData()
formData.append('file', file)
formData.append('tenant_id', tenantId)
formData.append('user_id', userId)
formData.append('is_public', 'false')
const response = await fetch('http://localhost:8090/api/files', {
method: 'POST',
body: formData,
})
// Read file (display image)
<img src={`http://localhost:8090/api/read/${filePath}`} />
// Download file
window.open(`http://localhost:8090/api/download/${filePath}`)
Backend Service (Node.js)
import FormData from 'form-data'
import fs from 'fs'
const formData = new FormData()
formData.append('file', fs.createReadStream('path/to/file.pdf'))
formData.append('tenant_id', tenantId)
const response = await fetch('http://localhost:8090/api/files', {
method: 'POST',
body: formData,
headers: formData.getHeaders(),
})
Troubleshooting
File tidak terupload ke object storage
- Pastikan AWS credentials sudah dikonfigurasi di
.env - Pastikan
AWS_S3_BUCKET_NAMEsudah benar - Check logs untuk error message
- Service akan otomatis fallback ke local storage jika object storage gagal
Database connection error
- Pastikan
DATABASE_URLsudah benar - Pastikan database
lania_commonsudah ada - Pastikan table
file_uploadssudah ada di database
License
ISC