59 lines
2.0 KiB
JavaScript
59 lines
2.0 KiB
JavaScript
import express from 'express';
|
|
import cors from 'cors';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { fileURLToPath } from 'url';
|
|
import boardRoutes from './routes/boardRoutes.js';
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
export function createApp() {
|
|
const app = express();
|
|
// CORS configuration
|
|
app.use(cors({
|
|
origin: (origin, callback) => {
|
|
callback(null, true);
|
|
},
|
|
credentials: true,
|
|
}));
|
|
app.use(express.json());
|
|
// Health check endpoint
|
|
app.get('/health', (_req, res) => {
|
|
res.json({
|
|
status: 'ok',
|
|
service: 'retro-kanban-server',
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
});
|
|
// API Routes
|
|
app.use('/api/boards', boardRoutes);
|
|
// Serve static frontend assets in production (when client build exists)
|
|
const clientDistPaths = [
|
|
path.join(__dirname, '../public'),
|
|
path.join(__dirname, '../../client/dist'),
|
|
path.join(__dirname, '../client/dist'),
|
|
path.join(process.cwd(), 'client/dist'),
|
|
path.join(process.cwd(), 'public'),
|
|
];
|
|
let staticPath = clientDistPaths.find((p) => fs.existsSync(p));
|
|
if (staticPath) {
|
|
console.log(`📁 [Static Assets] Serving frontend from: ${staticPath}`);
|
|
app.use(express.static(staticPath));
|
|
// SPA fallback: any non-API route serves index.html
|
|
app.get('*', (req, res, next) => {
|
|
if (req.path.startsWith('/api') || req.path.startsWith('/socket.io')) {
|
|
return next();
|
|
}
|
|
res.sendFile(path.join(staticPath, 'index.html'));
|
|
});
|
|
}
|
|
// Global Error Handler
|
|
app.use((err, _req, res, _next) => {
|
|
console.error('Unhandled server error:', err);
|
|
res.status(500).json({
|
|
error: 'Internal Server Error',
|
|
message: process.env.NODE_ENV === 'development' ? err.message : undefined,
|
|
});
|
|
});
|
|
return app;
|
|
}
|