workspace/projects/erp-suite/apps/verticales/retail/backend/src/app.ts
Adrian Flores Cortes e360b88612
Some checks are pending
CI Pipeline / changes (push) Waiting to run
CI Pipeline / core (push) Blocked by required conditions
CI Pipeline / trading-backend (push) Blocked by required conditions
CI Pipeline / trading-data-service (push) Blocked by required conditions
CI Pipeline / trading-frontend (push) Blocked by required conditions
CI Pipeline / erp-core (push) Blocked by required conditions
CI Pipeline / erp-mecanicas (push) Blocked by required conditions
CI Pipeline / gamilit-backend (push) Blocked by required conditions
CI Pipeline / gamilit-frontend (push) Blocked by required conditions
changes on erp
2025-12-18 06:25:52 -06:00

121 lines
3.1 KiB
TypeScript

import 'reflect-metadata';
import express, { Application, Request, Response, NextFunction } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import morgan from 'morgan';
// Route imports
import branchRoutes from './modules/branches/routes/branch.routes';
import posRoutes from './modules/pos/routes/pos.routes';
// Error type
interface AppError extends Error {
statusCode?: number;
status?: string;
isOperational?: boolean;
}
// Create Express app
const app: Application = express();
// Security middleware
app.use(helmet());
// CORS configuration
app.use(cors({
origin: process.env.CORS_ORIGIN?.split(',') || ['http://localhost:3000', 'http://localhost:5173'],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Tenant-ID', 'X-Branch-ID'],
}));
// Compression
app.use(compression());
// Body parsing
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
// Request logging
if (process.env.NODE_ENV !== 'test') {
app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));
}
// Health check endpoint
app.get('/health', (_req: Request, res: Response) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
version: process.env.npm_package_version || '0.1.0',
environment: process.env.NODE_ENV || 'development',
});
});
// API version info
app.get('/api', (_req: Request, res: Response) => {
res.json({
name: 'ERP Retail API',
version: '0.1.0',
modules: [
'branches',
'pos',
'cash',
'inventory',
'customers',
'pricing',
'invoicing',
'ecommerce',
'purchases',
],
});
});
// API Routes
app.use('/api/branches', branchRoutes);
app.use('/api/pos', posRoutes);
// TODO: Add remaining route modules as they are implemented
// app.use('/api/cash', cashRouter);
// app.use('/api/inventory', inventoryRouter);
// app.use('/api/customers', customersRouter);
// app.use('/api/pricing', pricingRouter);
// app.use('/api/invoicing', invoicingRouter);
// app.use('/api/ecommerce', ecommerceRouter);
// app.use('/api/purchases', purchasesRouter);
// 404 handler
app.use((_req: Request, res: Response) => {
res.status(404).json({
success: false,
error: {
code: 'NOT_FOUND',
message: 'The requested resource was not found',
},
});
});
// Global error handler
app.use((err: AppError, _req: Request, res: Response, _next: NextFunction) => {
const statusCode = err.statusCode || 500;
const status = err.status || 'error';
// Log error
console.error('Error:', {
message: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
statusCode,
});
// Send response
res.status(statusCode).json({
success: false,
error: {
code: status.toUpperCase().replace(/ /g, '_'),
message: err.isOperational ? err.message : 'An unexpected error occurred',
...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
},
});
});
export default app;