require('dotenv').config(); const express = require('express'); const { Pool } = require('pg'); const session = require('express-session'); const cors = require('cors'); const path = require('path'); const bcrypt = require('bcryptjs'); // ====================== // App init // ====================== const app = express(); const PORT = process.env.PORT || 3000; // ====================== // Middleware // ====================== app.use(cors()); app.use(express.json()); app.use(express.static(path.join(__dirname, 'public'))); // ====================== // Session // ====================== app.use(session({ secret: process.env.SESSION_SECRET || 'change-this-secret', resave: false, saveUninitialized: false, cookie: { secure: process.env.NODE_ENV === 'production', httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 } })); // ====================== // Database // ====================== const pool = new Pool({ host: process.env.DB_HOST || 'postgres', // важно для Docker port: process.env.DB_PORT || 5432, database: process.env.DB_NAME || 'postgres', user: process.env.DB_USER || 'postgres', password: process.env.DB_PASSWORD || 'postgres', }); // Проверка подключения pool.connect((err, client, release) => { if (err) { console.error('❌ PostgreSQL connection error:', err.message); } else { console.log('✅ PostgreSQL connected'); release(); } }); // ====================== // Init DB // ====================== async function initializeDatabase() { const client = await pool.connect(); try { await client.query(` CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(255), email VARCHAR(255) UNIQUE, password VARCHAR(255), role VARCHAR(50) DEFAULT 'viewer', created_at TIMESTAMP DEFAULT NOW() ); `); const exists = await client.query( 'SELECT id FROM users WHERE email = $1', ['admin@example.com'] ); if (exists.rows.length === 0) { const hash = await bcrypt.hash('admin123', 10); await client.query( `INSERT INTO users (name, email, password, role) VALUES ($1, $2, $3, $4)`, ['Admin', 'admin@example.com', hash, 'superadmin'] ); console.log('✅ Default admin created'); } } catch (err) { console.error('DB init error:', err); } finally { client.release(); } } initializeDatabase(); // ====================== // Routes // ====================== const authRoutes = require('./src/routes/auth'); const userRoutes = require('./src/routes/users'); const dbRoutes = require('./src/routes/db-tables'); const adminRoutes = require('./src/routes/admin'); app.use('/api/auth', authRoutes(pool)); app.use('/api/users', userRoutes(pool)); app.use('/api/db', dbRoutes(pool)); app.use('/api/admin', adminRoutes(pool)); // ====================== // SPA fallback // ====================== app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); // ====================== // Error handler // ====================== app.use((err, req, res, next) => { console.error(err); res.status(500).json({ error: 'Internal server error' }); }); // ====================== // Start server // ====================== app.listen(PORT, '0.0.0.0', () => { console.log(`🚀 Server running on http://localhost:${PORT}`); }); // ====================== // Graceful shutdown // ====================== process.on('SIGTERM', () => { console.log('SIGTERM received. Shutting down...'); pool.end(() => { console.log('DB pool closed'); process.exit(0); }); }); module.exports = app;