feat(prod): production deployment fixes - env loader, mongoose module, CSS static files, security hardening, PDF export, new UI components

This commit is contained in:
Rafif-Riqullah-Siregar committed 2026-07-16 13:14:34 +07:00
1 parent a403f752f3
commit 46f33eb088
69 files changed
+7367 -744

No files matched your search

+2 -1
View File
@@ -5,7 +5,8 @@
const mongoose = require('mongoose');
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '../../.env.local') });
const envFile = process.env.NODE_ENV === 'production' ? '.env.production' : '.env.local';
require('dotenv').config({ path: path.join(__dirname, '../../', envFile) });
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
+18 -1
View File
@@ -50,7 +50,24 @@ const storage = multer.diskStorage({
cb(null, `profile-${uniqueSuffix}${path.extname(file.originalname)}`);
}
});
const upload = multer({ storage });
// File filter — only allow image formats for profile picture uploads
function imageFileFilter(req, file, cb) {
const allowedMimeTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
if (allowedMimeTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('Invalid file type. Only JPEG, PNG, and WebP images are allowed.'), false);
}
}
const upload = multer({
storage,
fileFilter: imageFileFilter,
limits: {
fileSize: 5 * 1024 * 1024, // 5 MB maximum per profile picture
},
});
module.exports = {
JWT_SECRET,
+17 -6
View File
@@ -1,5 +1,10 @@
// backend/server.js
// ─────────────────────────────────────────────────────────────────────────────
// Polyfill global crypto for Node 18 compatibility (required by mongodb driver)
if (typeof globalThis.crypto === 'undefined') {
globalThis.crypto = require('crypto');
}
// BackOne Backend API Server
//
// Tanggung jawab backend ini adalah READ-ONLY dari MongoDB.
@@ -15,7 +20,8 @@
// ─────────────────────────────────────────────────────────────────────────────
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const envFile = process.env.NODE_ENV === 'production' ? '.env.production' : '.env.local';
require('dotenv').config({ path: path.join(__dirname, '..', envFile) });
const express = require('express');
const cors = require('cors');
@@ -45,7 +51,8 @@ app.use(cors({
},
credentials: true
}));
app.use(express.json());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.use(cookieParser());
// ─── Public Routes ────────────────────────────────────────────────────────────
@@ -116,8 +123,12 @@ app.get('/api/health', (req, res) => {
});
// ─── Start Server ─────────────────────────────────────────────────────────────
app.listen(PORT, () => {
console.log(`\n🚀 BackOne API Server berjalan di http://localhost:${PORT}`);
console.log(`🔌 API Health : http://localhost:${PORT}/api/health`);
console.log(`📡 Mode : READ-ONLY dari MongoDB (data dikirim oleh Proxy Server)\n`);
// Bind to 127.0.0.1 in production to prevent direct external access to port 3001.
// All external traffic must go through the reverse proxy (Apache/Nginx) at port 80/443.
const BIND_HOST = process.env.NODE_ENV === 'production' ? '127.0.0.1' : '0.0.0.0';
app.listen(PORT, BIND_HOST, () => {
console.log(`\n🚀 BackOne API Server berjalan di http://${BIND_HOST}:${PORT}`);
console.log(`🔌 API Health : http://${BIND_HOST}:${PORT}/api/health`);
console.log(`📡 Mode : READ-ONLY dari MongoDB (data dikirim oleh Proxy Server)`);
console.log(`🔒 Security : Bound to ${BIND_HOST} (internal only in production)\n`);
});