Files
smanab/server.js
2026-02-22 14:54:55 +08:00

123 lines
3.9 KiB
JavaScript
Executable File

// Main Server - MySQL Backend for Absensi Siswa
import express from 'express';
import cors from 'cors';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
// Import database and schema
import pool, { testConnection } from './backend/db.js';
import createTables from './backend/schema.js';
// Import routes
import usersRoutes from './backend/routes/users.js';
import attendanceRoutes from './backend/routes/attendance.js';
import registrationsRoutes from './backend/routes/registrations.js';
import settingsRoutes from './backend/routes/settings.js';
import authRoutes from './backend/routes/auth.js';
import staffRoutes from './backend/routes/staff.js';
import leaveRequestsRoutes from './backend/routes/leaveRequests.js';
import cron from 'node-cron';
import { runAutoRekapAlfa } from './backend/routes/attendance.js';
// Define __dirname for ES Modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
const port = process.env.PORT || 3010;
// Middleware
app.use(cors({
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));
// API Routes
app.use('/api/users', usersRoutes);
app.use('/api/attendance', attendanceRoutes);
app.use('/api/registrations', registrationsRoutes);
app.use('/api/settings', settingsRoutes);
app.use('/api/auth', authRoutes);
app.use('/api/staff', staffRoutes);
app.use('/api/leave-requests', leaveRequestsRoutes);
// Health check endpoint
app.get('/api/health', async (req, res) => {
try {
// Ping database
await pool.query('SELECT 1');
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
database: 'connected',
dbName: process.env.DB_NAME,
port: port
});
} catch (error) {
console.error('Health Check Failed:', error);
res.status(500).json({
status: 'error',
database: 'disconnected',
error: error.message
});
}
});
// Serve static files from the 'dist' directory (Vite build output)
app.use(express.static(path.join(__dirname, 'dist')));
// Handle SPA routing: return index.html for any unknown routes
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});
// Initialize database and start server
const startServer = async () => {
try {
// 1. Test database connection
await testConnection();
// 2. Initialize database schema
await createTables();
// 3. Start server
app.listen(port, async () => {
console.log(`\n🚀 Server is running on port ${port}`);
console.log(`📍 Local: http://localhost:${port}`);
console.log(`📊 API: http://localhost:${port}/api/health`);
console.log(`🗃️ Database: ${process.env.DB_NAME}@${process.env.DB_HOST}`);
// 4. Initialize Scheduler (Cron Job) - Read time from database
try {
const pool = (await import('./backend/db.js')).default;
const [timeRow] = await pool.query("SELECT setting_value FROM settings WHERE setting_key = 'AUTO_REKAP_ALFA_TIME'");
const rekapTime = timeRow.length > 0 ? timeRow[0].setting_value : '19:00';
const [hour, minute] = rekapTime.split(':');
cron.schedule(`${minute} ${hour} * * *`, async () => {
console.log(`⏰ [Cron] Running scheduled Alfa rekap at ${rekapTime}...`);
await runAutoRekapAlfa();
}, {
timezone: "Asia/Makassar" // WITA
});
console.log(`⏰ Scheduler initialized (Auto-Rekap Alfa at ${rekapTime} WITA)`);
} catch (cronError) {
console.error('⏰ Scheduler initialization failed:', cronError.message);
}
});
} catch (error) {
console.error('❌ Server startup failed:', error.message);
process.exit(1);
}
};
startServer();