You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

378 lines
15 KiB

const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
require('dotenv').config();
// Import models and associations
const sequelize = require('./config/database');
require('./models/associations');
const app = express();
const PORT = process.env.PORT || 3000;
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: {
success: false,
message: 'Too many requests from this IP, please try again later.'
}
});
// Middleware
app.use(limiter);
app.use(helmet());
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
success: true,
message: 'Restaurant API is running!',
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV || 'development'
});
});
// API Documentation endpoint
app.get('/api/docs', (req, res) => {
const baseUrl = `${req.protocol}://${req.get('host')}`;
res.json({
success: true,
message: 'Restaurant Management API Documentation',
version: '1.0.0',
baseUrl: baseUrl,
endpoints: {
// Table Management
tables: {
description: 'Gestion des tables du restaurant',
endpoints: {
'GET /api/tables': 'Obtenir toutes les tables',
'GET /api/tables/stats': 'Statistiques des tables',
'GET /api/tables/:id': 'Obtenir une table par ID',
'POST /api/tables': 'Créer une nouvelle table',
'PUT /api/tables/:id': 'Mettre à jour une table',
'DELETE /api/tables/:id': 'Supprimer une table'
},
queryParams: {
'GET /api/tables': {
page: 'Numéro de page (défaut: 1)',
limit: 'Nombre d\'éléments par page (défaut: 10)',
status: 'Filtrer par statut (available, occupied, reserved, maintenance)',
location: 'Filtrer par emplacement',
capacity_min: 'Capacité minimale',
capacity_max: 'Capacité maximale',
sort_by: 'Champ de tri (défaut: created_at)',
sort_order: 'Ordre de tri (ASC, DESC)'
}
},
sampleRequest: {
'POST /api/tables': {
nom: 'Table VIP 1',
capacity: 4,
status: 'available',
location: 'Main Hall'
}
}
},
// Menu Categories Management
menuCategories: {
description: 'Gestion des catégories de menu',
endpoints: {
'GET /api/menu-categories': 'Obtenir toutes les catégories',
'GET /api/menu-categories/:id': 'Obtenir une catégorie par ID',
'POST /api/menu-categories': 'Créer une nouvelle catégorie',
'PUT /api/menu-categories/:id': 'Mettre à jour une catégorie',
'DELETE /api/menu-categories/:id': 'Supprimer une catégorie'
},
sampleRequest: {
'POST /api/menu-categories': {
nom: 'Entrées',
description: 'Plats d\'entrée',
ordre: 1,
actif: true
}
}
},
// Menu Management
menus: {
description: 'Gestion des plats du menu',
endpoints: {
'GET /api/menus': 'Obtenir tous les plats',
'GET /api/menus/stats': 'Statistiques des menus',
'GET /api/menus/category/:categoryId': 'Obtenir les plats par catégorie',
'GET /api/menus/:id': 'Obtenir un plat par ID',
'POST /api/menus': 'Créer un nouveau plat',
'PUT /api/menus/:id': 'Mettre à jour un plat',
'DELETE /api/menus/:id': 'Supprimer un plat'
},
queryParams: {
'GET /api/menus': {
page: 'Numéro de page (défaut: 1)',
limit: 'Nombre d\'éléments par page (défaut: 10)',
search: 'Rechercher par nom',
category_id: 'Filtrer par catégorie',
disponible: 'Filtrer par disponibilité (true/false)',
prix_min: 'Prix minimum',
prix_max: 'Prix maximum'
}
},
sampleRequest: {
'POST /api/menus': {
nom: 'Salade César',
commentaire: 'Salade fraîche avec croûtons',
prix: 12.50,
categorie_id: 1,
disponible: true,
ingredients: 'Salade, croûtons, parmesan',
allergenes: 'Gluten, Lactose',
calories: 350
}
}
},
// Client Management
clients: {
description: 'Gestion des clients',
endpoints: {
'GET /api/clients': 'Obtenir tous les clients',
'GET /api/clients/stats': 'Statistiques des clients',
'GET /api/clients/:id': 'Obtenir un client par ID',
'POST /api/clients': 'Créer un nouveau client',
'PUT /api/clients/:id': 'Mettre à jour un client',
'DELETE /api/clients/:id': 'Supprimer un client'
},
queryParams: {
'GET /api/clients': {
page: 'Numéro de page (défaut: 1)',
limit: 'Nombre d\'éléments par page (défaut: 10)',
search: 'Rechercher par nom, prénom, email ou téléphone',
actif: 'Filtrer par statut actif (true/false)',
sort_by: 'Champ de tri (défaut: created_at)',
sort_order: 'Ordre de tri (ASC, DESC)'
}
},
sampleRequest: {
'POST /api/clients': {
nom: 'Dupont',
prenom: 'Jean',
email: 'jean.dupont@email.com',
telephone: '0123456789',
adresse: '123 Rue de la Paix, Paris',
date_naissance: '1980-05-15'
}
}
},
// Reservation Management
reservations: {
description: 'Gestion des réservations',
endpoints: {
'GET /api/reservations': 'Obtenir toutes les réservations',
'GET /api/reservations/stats': 'Statistiques des réservations',
'GET /api/reservations/today': 'Réservations du jour',
'GET /api/reservations/status/:status': 'Réservations par statut',
'GET /api/reservations/:id': 'Obtenir une réservation par ID',
'POST /api/reservations': 'Créer une nouvelle réservation',
'PUT /api/reservations/:id': 'Mettre à jour une réservation',
'DELETE /api/reservations/:id': 'Supprimer une réservation'
},
queryParams: {
'GET /api/reservations': {
page: 'Numéro de page (défaut: 1)',
limit: 'Nombre d\'éléments par page (défaut: 10)',
statut: 'Filtrer par statut (en_attente, confirmee, annulee, terminee)',
date_debut: 'Date de début (YYYY-MM-DD)',
date_fin: 'Date de fin (YYYY-MM-DD)',
table_id: 'Filtrer par table'
}
},
sampleRequest: {
'POST /api/reservations': {
client_id: 1,
table_id: 1,
date_reservation: '2025-01-28 19:30:00',
nombre_personnes: 4,
commentaires: 'Anniversaire',
statut: 'en_attente'
}
},
statusValues: ['en_attente', 'confirmee', 'annulee', 'terminee']
},
// Order Management
commandes: {
description: 'Gestion des commandes',
endpoints: {
'GET /api/commandes': 'Obtenir toutes les commandes',
'GET /api/commandes/stats': 'Statistiques des commandes',
'GET /api/commandes/kitchen': 'Commandes pour la cuisine',
'GET /api/commandes/status/:status': 'Commandes par statut',
'GET /api/commandes/:id': 'Obtenir une commande par ID',
'POST /api/commandes': 'Créer une nouvelle commande',
'PUT /api/commandes/:id/status': 'Mettre à jour le statut d\'une commande',
'DELETE /api/commandes/:id': 'Supprimer une commande'
},
queryParams: {
'GET /api/commandes': {
page: 'Numéro de page (défaut: 1)',
limit: 'Nombre d\'éléments par page (défaut: 10)',
statut: 'Filtrer par statut',
date_debut: 'Date de début (YYYY-MM-DD)',
date_fin: 'Date de fin (YYYY-MM-DD)',
table_id: 'Filtrer par table',
client_id: 'Filtrer par client'
}
},
sampleRequest: {
'POST /api/commandes': {
client_id: 1,
table_id: 1,
reservation_id: 1,
serveur: 'Marie',
commentaires: 'Sans oignons',
items: [
{
menu_id: 1,
quantite: 2,
commentaires: 'Bien cuit'
},
{
menu_id: 2,
quantite: 1
}
]
},
'PUT /api/commandes/:id/status': {
statut: 'en_preparation',
mode_paiement: 'carte',
serveur: 'Marie'
}
},
statusValues: ['en_attente', 'en_preparation', 'prete', 'servie', 'payee', 'annulee']
}
},
// Common Response Format
responseFormat: {
success: {
success: true,
data: '...',
message: 'Optional success message'
},
error: {
success: false,
message: 'Error description',
error: 'Detailed error message'
},
pagination: {
success: true,
data: {
items: '...',
pagination: {
currentPage: 1,
totalPages: 10,
totalItems: 100,
itemsPerPage: 10
}
}
}
},
// Common HTTP Status Codes
statusCodes: {
200: 'OK - Successful GET, PUT',
201: 'Created - Successful POST',
400: 'Bad Request - Invalid data',
404: 'Not Found - Resource not found',
500: 'Internal Server Error - Server error'
}
});
});
// Import routes
const tableRoutes = require('./routes/tableRoutes');
const menuCategoryRoutes = require('./routes/menuCategoryRoutes');
const menuRoutes = require('./routes/menuRoutes');
const clientRoutes = require('./routes/clientRoutes');
const reservationRoutes = require('./routes/reservationRoutes');
const commandeRoutes = require('./routes/commandeRoutes');
// Use routes
app.use('/api/tables', tableRoutes);
app.use('/api/menu-categories', menuCategoryRoutes);
app.use('/api/menus', menuRoutes);
app.use('/api/clients', clientRoutes);
app.use('/api/reservations', reservationRoutes);
app.use('/api/commandes', commandeRoutes);
// 404 handler
app.use('*', (req, res) => {
res.status(404).json({
success: false,
message: 'Route not found',
availableRoutes: {
documentation: '/api/docs',
health: '/health',
tables: '/api/tables',
menuCategories: '/api/menu-categories',
menus: '/api/menus',
clients: '/api/clients',
reservations: '/api/reservations',
orders: '/api/commandes'
}
});
});
// Global error handler
app.use((error, req, res, next) => {
console.error('Global Error:', error);
res.status(error.status || 500).json({
success: false,
message: error.message || 'Internal server error',
...(process.env.NODE_ENV === 'development' && { stack: error.stack })
});
});
// Start server function
const startServer = async () => {
try {
// Test database connection
await sequelize.authenticate();
console.log('✅ Database connection established successfully.');
// Sync database models
await sequelize.sync({ alter: false });
console.log('✅ Database synchronized successfully.');
// Start server
app.listen(PORT, () => {
console.log(`🚀 Server is running on port ${PORT}`);
console.log(`📚 API Documentation: http://localhost:${PORT}/api/docs`);
console.log(`❤️ Health Check: http://localhost:${PORT}/health`);
console.log('🔗 Available endpoints:');
console.log(' - Tables: /api/tables');
console.log(' - Menu Categories: /api/menu-categories');
console.log(' - Menus: /api/menus');
console.log(' - Clients: /api/clients');
console.log(' - Reservations: /api/reservations');
console.log(' - Orders: /api/commandes');
});
} catch (error) {
console.error('❌ Unable to start server:', error);
process.exit(1);
}
};
// Start the server
startServer();
module.exports = app;