- Implement PostgreSQL database schema with users and bookmarks tables - Add database connection pooling with retry logic and error handling - Create migration system with automatic schema initialization - Add database CLI tools for management (init, status, validate, etc.) - Include comprehensive error handling and diagnostics - Add development seed data and testing utilities - Implement health monitoring and connection pool statistics - Create detailed documentation and troubleshooting guide Database features: - Users table with authentication fields and email verification - Bookmarks table with user association and metadata - Proper indexes for performance optimization - Automatic timestamp triggers - Transaction support with rollback handling - Connection pooling (20 max connections, 30s idle timeout) - Graceful shutdown handling CLI commands available: - npm run db:init - Initialize database - npm run db:status - Check database status - npm run db:validate - Validate schema - npm run db:test - Run database tests - npm run db:diagnostics - Full diagnostics
113 lines
2.9 KiB
JavaScript
113 lines
2.9 KiB
JavaScript
const express = require('express');
|
|
const helmet = require('helmet');
|
|
const rateLimit = require('express-rate-limit');
|
|
const cookieParser = require('cookie-parser');
|
|
require('dotenv').config();
|
|
|
|
const app = express();
|
|
|
|
// Security middleware
|
|
app.use(helmet());
|
|
|
|
// Rate limiting
|
|
const limiter = rateLimit({
|
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
max: 100, // limit each IP to 100 requests per windowMs
|
|
message: 'Too many requests from this IP, please try again later.'
|
|
});
|
|
app.use(limiter);
|
|
|
|
// Body parsing middleware
|
|
app.use(express.json({ limit: '10mb' }));
|
|
app.use(express.urlencoded({ extended: true }));
|
|
app.use(cookieParser());
|
|
|
|
// CORS middleware
|
|
app.use((req, res, next) => {
|
|
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'];
|
|
const origin = req.headers.origin;
|
|
|
|
if (allowedOrigins.includes(origin)) {
|
|
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
}
|
|
|
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
|
|
if (req.method === 'OPTIONS') {
|
|
res.sendStatus(200);
|
|
} else {
|
|
next();
|
|
}
|
|
});
|
|
|
|
// Health check endpoint
|
|
app.get('/health', async (req, res) => {
|
|
try {
|
|
const dbConnection = require('./database/connection');
|
|
const dbUtils = require('./database/utils');
|
|
|
|
const health = await dbConnection.healthCheck();
|
|
const diagnostics = await dbUtils.diagnostics();
|
|
|
|
res.json({
|
|
status: health.healthy ? 'OK' : 'ERROR',
|
|
timestamp: new Date().toISOString(),
|
|
database: health,
|
|
diagnostics: diagnostics
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
status: 'ERROR',
|
|
timestamp: new Date().toISOString(),
|
|
error: error.message
|
|
});
|
|
}
|
|
});
|
|
|
|
// Database status endpoint
|
|
app.get('/db-status', async (req, res) => {
|
|
try {
|
|
const dbInitializer = require('./database/init');
|
|
const dbUtils = require('./database/utils');
|
|
|
|
const status = await dbInitializer.getStatus();
|
|
const validation = await dbUtils.validateSchema();
|
|
|
|
res.json({
|
|
timestamp: new Date().toISOString(),
|
|
...status,
|
|
schema: validation
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
error: error.message,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
});
|
|
|
|
// API routes will be added here
|
|
// app.use('/api/auth', require('./routes/auth'));
|
|
// app.use('/api/user', require('./routes/user'));
|
|
// app.use('/api/bookmarks', require('./routes/bookmarks'));
|
|
|
|
// Error handling middleware
|
|
app.use((err, req, res, next) => {
|
|
console.error(err.stack);
|
|
res.status(500).json({
|
|
error: 'Something went wrong!',
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
});
|
|
|
|
// 404 handler
|
|
app.use((req, res) => {
|
|
res.status(404).json({
|
|
error: 'Route not found',
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
});
|
|
|
|
module.exports = app; |