Files

153 lines
4.4 KiB
TypeScript

import { Application, Router } from "@oak/oak";
import { config } from "./config/env.ts";
import { db } from "./config/database.ts";
import {
cors,
rateLimit,
requestLogger,
securityHeaders,
} from "./middleware/security.ts";
// Import routes
import authRoutes from "./routes/auth.ts";
import userRoutes from "./routes/users.ts";
import departmentRoutes from "./routes/departments.ts";
import workAllocationRoutes from "./routes/work-allocations.ts";
import attendanceRoutes from "./routes/attendance.ts";
import contractorRateRoutes from "./routes/contractor-rates.ts";
import employeeSwapRoutes from "./routes/employee-swaps.ts";
import reportRoutes from "./routes/reports.ts";
import standardRateRoutes from "./routes/standard-rates.ts";
import activityRoutes from "./routes/activities.ts";
// Initialize database connection
await db.connect();
// Create Oak application
const app = new Application();
// Global error handler
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
const error = err as Error & { status?: number };
console.error("Error:", error.message);
ctx.response.status = error.status || 500;
ctx.response.body = {
error: config.isDevelopment() ? error.message : "Internal server error",
};
}
});
// Apply security middleware
app.use(cors);
app.use(securityHeaders);
app.use(requestLogger);
// Rate limiting (only in production or if enabled)
if (config.isProduction()) {
app.use(rateLimit);
}
// Create main router
const router = new Router();
// Health check endpoint
router.get("/health", (ctx) => {
ctx.response.body = {
status: "ok",
timestamp: new Date().toISOString(),
version: "2.0.0-deno",
runtime: "Deno",
};
});
// Mount API routes
router.use("/api/auth", authRoutes.routes(), authRoutes.allowedMethods());
router.use("/api/users", userRoutes.routes(), userRoutes.allowedMethods());
router.use(
"/api/departments",
departmentRoutes.routes(),
departmentRoutes.allowedMethods(),
);
router.use(
"/api/work-allocations",
workAllocationRoutes.routes(),
workAllocationRoutes.allowedMethods(),
);
router.use(
"/api/attendance",
attendanceRoutes.routes(),
attendanceRoutes.allowedMethods(),
);
router.use(
"/api/contractor-rates",
contractorRateRoutes.routes(),
contractorRateRoutes.allowedMethods(),
);
router.use(
"/api/employee-swaps",
employeeSwapRoutes.routes(),
employeeSwapRoutes.allowedMethods(),
);
router.use(
"/api/reports",
reportRoutes.routes(),
reportRoutes.allowedMethods(),
);
router.use(
"/api/standard-rates",
standardRateRoutes.routes(),
standardRateRoutes.allowedMethods(),
);
router.use(
"/api/activities",
activityRoutes.routes(),
activityRoutes.allowedMethods(),
);
// Apply routes
app.use(router.routes());
app.use(router.allowedMethods());
// 404 handler
app.use((ctx) => {
ctx.response.status = 404;
ctx.response.body = { error: "Route not found" };
});
// Graceful shutdown
const controller = new AbortController();
Deno.addSignalListener("SIGINT", () => {
console.log("\n🛑 Shutting down gracefully...");
controller.abort();
db.close();
Deno.exit(0);
});
Deno.addSignalListener("SIGTERM", () => {
console.log("\n🛑 Shutting down gracefully...");
controller.abort();
db.close();
Deno.exit(0);
});
// Start server
console.log(`
╔════════════════════════════════════════════════════════════╗
║ Work Allocation System - Deno Backend v2.0.0 ║
╠════════════════════════════════════════════════════════════╣
║ 🦕 Runtime: Deno ${Deno.version.deno}
║ 🔒 TypeScript with strict type checking ║
║ 🛡️ Security: Rate limiting, CORS, XSS protection ║
╚════════════════════════════════════════════════════════════╝
`);
console.log(`🚀 Server running on http://localhost:${config.PORT}`);
console.log(`📊 Health check: http://localhost:${config.PORT}/health`);
console.log(`🔧 Environment: ${config.NODE_ENV}`);
await app.listen({ port: config.PORT, signal: controller.signal });