Adds initial models, migrations, and services to support role-based access and sharing; wires routes to prepare for permission-driven features.
178 lines
4.9 KiB
JavaScript
178 lines
4.9 KiB
JavaScript
require('dotenv').config();
|
|
const express = require('express');
|
|
const path = require('path');
|
|
const cors = require('cors');
|
|
const helmet = require('helmet');
|
|
const compression = require('compression');
|
|
const morgan = require('morgan');
|
|
const session = require('express-session');
|
|
const SequelizeStore = require('connect-session-sequelize')(session.Store);
|
|
const { sequelize } = require('./models');
|
|
const { initializeTelegramPolling } = require('./services/telegramInitializer');
|
|
const taskScheduler = require('./services/taskScheduler');
|
|
const { setConfig, getConfig } = require('./config/config');
|
|
const config = getConfig();
|
|
|
|
const app = express();
|
|
|
|
// Session store
|
|
const sessionStore = new SequelizeStore({
|
|
db: sequelize,
|
|
});
|
|
|
|
// Middlewares
|
|
app.use(
|
|
helmet({
|
|
hsts: false,
|
|
forceHTTPS: false,
|
|
contentSecurityPolicy: false,
|
|
})
|
|
);
|
|
app.use(compression());
|
|
app.use(morgan('combined'));
|
|
|
|
// CORS configuration
|
|
app.use(
|
|
cors({
|
|
origin: config.allowedOrigins,
|
|
credentials: true,
|
|
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
|
allowedHeaders: [
|
|
'Authorization',
|
|
'Content-Type',
|
|
'Accept',
|
|
'X-Requested-With',
|
|
],
|
|
exposedHeaders: ['Content-Type'],
|
|
maxAge: 1728000,
|
|
})
|
|
);
|
|
|
|
// Body parsing
|
|
app.use(express.json({ limit: '10mb' }));
|
|
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
|
|
|
|
// Session configuration
|
|
app.use(
|
|
session({
|
|
secret: config.secret,
|
|
store: sessionStore,
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
cookie: {
|
|
httpOnly: true,
|
|
secure: false,
|
|
maxAge: 2592000000, // 30 days
|
|
sameSite: 'lax',
|
|
},
|
|
})
|
|
);
|
|
|
|
// Static files
|
|
if (config.production) {
|
|
app.use(express.static(path.join(__dirname, 'dist')));
|
|
} else {
|
|
app.use(express.static('public'));
|
|
}
|
|
|
|
// Serve locales
|
|
if (config.production) {
|
|
app.use('/locales', express.static(path.join(__dirname, 'dist/locales')));
|
|
} else {
|
|
app.use(
|
|
'/locales',
|
|
express.static(path.join(__dirname, '../public/locales'))
|
|
);
|
|
}
|
|
|
|
// Serve uploaded files
|
|
app.use('/api/uploads', express.static(config.uploadPath));
|
|
|
|
// Authentication middleware
|
|
const { requireAuth } = require('./middleware/auth');
|
|
|
|
// Health check (before auth middleware) - ensure it's completely bypassed
|
|
app.get('/api/health', (req, res) => {
|
|
res.status(200).json({
|
|
status: 'ok',
|
|
timestamp: new Date().toISOString(),
|
|
uptime: process.uptime(),
|
|
environment: config.environment,
|
|
});
|
|
});
|
|
|
|
// Routes
|
|
app.use('/api', require('./routes/auth'));
|
|
app.use('/api', requireAuth, require('./routes/tasks'));
|
|
app.use('/api', requireAuth, require('./routes/projects'));
|
|
app.use('/api', requireAuth, require('./routes/admin'));
|
|
app.use('/api', requireAuth, require('./routes/shares'));
|
|
app.use('/api', requireAuth, require('./routes/areas'));
|
|
app.use('/api', requireAuth, require('./routes/notes'));
|
|
app.use('/api', requireAuth, require('./routes/tags'));
|
|
app.use('/api', requireAuth, require('./routes/users'));
|
|
app.use('/api', requireAuth, require('./routes/inbox'));
|
|
app.use('/api', requireAuth, require('./routes/url'));
|
|
app.use('/api', requireAuth, require('./routes/telegram'));
|
|
app.use('/api', requireAuth, require('./routes/quotes'));
|
|
app.use('/api', requireAuth, require('./routes/task-events'));
|
|
|
|
// SPA fallback
|
|
app.get('*', (req, res) => {
|
|
if (
|
|
!req.path.startsWith('/api/') &&
|
|
!req.path.match(/\.(js|css|png|jpg|jpeg|gif|ico|svg)$/)
|
|
) {
|
|
if (config.production) {
|
|
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
|
|
} else {
|
|
res.sendFile(path.join(__dirname, '../public', 'index.html'));
|
|
}
|
|
} else {
|
|
res.status(404).json({
|
|
error: 'Not Found',
|
|
message: 'The requested resource could not be found.',
|
|
});
|
|
}
|
|
});
|
|
|
|
// Error handling
|
|
app.use((err, req, res, next) => {
|
|
console.error(err.stack);
|
|
res.status(500).json({
|
|
error: 'Internal Server Error',
|
|
message: err.message,
|
|
});
|
|
});
|
|
|
|
// Initialize database and start server
|
|
async function startServer() {
|
|
try {
|
|
// Create session store table
|
|
await sessionStore.sync();
|
|
|
|
// Initialize Telegram polling after database is ready
|
|
await initializeTelegramPolling();
|
|
|
|
// Initialize task scheduler
|
|
await taskScheduler.initialize();
|
|
|
|
const server = app.listen(config.port, config.host, () => {
|
|
console.log(`Server running on port ${config.port}`);
|
|
console.log(`Server listening on http://localhost:${config.port}`);
|
|
});
|
|
|
|
server.on('error', (err) => {
|
|
console.error('Server error:', err);
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to start server:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
startServer();
|
|
}
|
|
|
|
module.exports = app;
|