Sergei 7d9e7e37bf Remove console.log statements and add structured logging
Created a centralized logger utility (src/utils/logger.js) that provides:
- Structured logging with context labels
- Log levels (ERROR, WARN, INFO, DEBUG)
- Environment-based log level control via LOG_LEVEL env variable
- Consistent timestamp and JSON data formatting

Removed console.log/error/warn statements from:
- All service files (mqtt, notifications, legacyAPI, email, storage, subscription-sync)
- All route handlers (auth, beneficiaries, deployments, webhook, admin, etc)
- Controllers (dashboard, auth, alarm)
- Database connection handler
- Main server file (index.js)

Preserved:
- Critical startup validation error for JWT_SECRET in index.js

Benefits:
- Production-ready logging that can be easily integrated with log aggregation services
- Reduced noise in production logs
- Easier debugging with structured context and data
- Configurable log levels per environment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-29 11:58:06 -08:00

126 lines
3.3 KiB
JavaScript

/**
* MinIO Storage Service
* S3-compatible object storage for media files
*
* MinIO Console: https://minio-console.eluxnetworks.net
* S3 Endpoint: https://minio.eluxnetworks.net
*/
const { S3Client, PutObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
const crypto = require('crypto');
// MinIO Configuration
const MINIO_ENDPOINT = process.env.MINIO_ENDPOINT || 'https://minio.eluxnetworks.net';
const MINIO_ACCESS_KEY = process.env.MINIO_ACCESS_KEY;
const MINIO_SECRET_KEY = process.env.MINIO_SECRET_KEY;
const MINIO_BUCKET = process.env.MINIO_BUCKET || 'wellnuo';
// Public URL for accessing files
const PUBLIC_URL = process.env.MINIO_PUBLIC_URL || MINIO_ENDPOINT;
// Create S3 client for MinIO
const s3Client = new S3Client({
endpoint: MINIO_ENDPOINT,
region: 'us-east-1', // MinIO ignores this but requires it
credentials: {
accessKeyId: MINIO_ACCESS_KEY,
secretAccessKey: MINIO_SECRET_KEY,
},
forcePathStyle: true, // Required for MinIO
});
/**
* Upload a base64 image to MinIO
* @param {string} base64Data - Base64 data URI (data:image/png;base64,...)
* @param {string} folder - Folder path (e.g., 'avatars/beneficiaries')
* @param {string} [filename] - Optional filename, generated if not provided
* @returns {Promise<{url: string, key: string}>}
*/
async function uploadBase64Image(base64Data, folder, filename = null) {
if (!MINIO_ACCESS_KEY || !MINIO_SECRET_KEY) {
throw new Error('MinIO credentials not configured');
}
// Parse base64 data URI
const matches = base64Data.match(/^data:image\/(\w+);base64,(.+)$/);
if (!matches) {
throw new Error('Invalid base64 image format');
}
const [, extension, base64Content] = matches;
const buffer = Buffer.from(base64Content, 'base64');
// Generate filename if not provided
const finalFilename = filename || `${crypto.randomUUID()}.${extension}`;
const key = `${folder}/${finalFilename}`;
// Determine content type
const contentType = `image/${extension === 'jpg' ? 'jpeg' : extension}`;
// Upload to MinIO
const command = new PutObjectCommand({
Bucket: MINIO_BUCKET,
Key: key,
Body: buffer,
ContentType: contentType,
ACL: 'public-read', // Make file publicly accessible
});
await s3Client.send(command);
// Return public URL
const url = `${PUBLIC_URL}/${MINIO_BUCKET}/${key}`;
return { url, key };
}
/**
* Delete a file from MinIO
* @param {string} key - Object key (path in bucket)
*/
async function deleteFile(key) {
if (!MINIO_ACCESS_KEY || !MINIO_SECRET_KEY) {
throw new Error('MinIO credentials not configured');
}
const command = new DeleteObjectCommand({
Bucket: MINIO_BUCKET,
Key: key,
});
await s3Client.send(command);
}
/**
* Extract key from MinIO URL
* @param {string} url - Full MinIO URL
* @returns {string|null} - Object key or null
*/
function extractKeyFromUrl(url) {
if (!url) return null;
// URL format: https://minio.eluxnetworks.net/wellnuo/avatars/xxx.png
const match = url.match(/\/wellnuo\/(.+)$/);
return match ? match[1] : null;
}
/**
* Check if storage is configured
*/
function isConfigured() {
return !!(MINIO_ACCESS_KEY && MINIO_SECRET_KEY);
}
module.exports = {
uploadBase64Image,
deleteFile,
extractKeyFromUrl,
isConfigured,
MINIO_BUCKET,
PUBLIC_URL,
};