{
  "slug": "express-starter",
  "runtimes": {
    "node": {
      "frameworks": {
        "express": {
          "dependencies": {
            "runtime": [
              "express",
              "cors",
              "dotenv-flow",
              "cross-env",
              "helmet",
              "cookie-parser",
              "pino",
              "pino-pretty",
              "source-map-support",
              "zod",
              "swagger-autogen",
              "swagger-ui-express"
            ],
            "dev": [
              "@types/express",
              "morgan",
              "@types/cors",
              "@types/morgan",
              "@types/cookie-parser",
              "@types/source-map-support",
              "@types/swagger-ui-express"
            ]
          },
          "env": [
            "LOG_LEVEL",
            "NODE_ENV",
            "PORT",
            "CORS_ORIGIN"
          ],
          "architectures": {
            "mvc": {
              "files": [
                {
                  "type": "file",
                  "path": "swagger.config.ts",
                  "content": "import swaggerAutoGen from \"swagger-autogen\";\n\nconst doc = {\n  info: {\n    title: \"Express Starter\",\n    description: \"Express Starter\",\n    version: \"1.0.0\"\n  },\n  host: `localhost:3000`,\n  schemes: [\"http\"]\n};\n\nconst outputFile = \"./src/docs/swagger.json\";\nconst endpointsFiles = [\"./src/routes/*.ts\"];\n\nswaggerAutoGen(outputFile, endpointsFiles, doc);\n"
                },
                {
                  "type": "file",
                  "path": "package.json",
                  "content": "{\n  \"name\": \"my-express-app\",\n  \"version\": \"1.0.0\",\n  \"main\": \"dist/server.js\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"cross-env NODE_ENV=development npx tsx watch src/server.ts\",\n    \"build\": \"rm -rf dist && tsc && tsc-alias\",\n    \"start\": \"cross-env NODE_ENV=production node dist/server.js\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"lint:check\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\",\n    \"format:check\": \"npx prettier . --check\",\n    \"format:fix\": \"npx prettier . --write\",\n    \"docs\": \"npx tsx swagger.config.ts\"\n  },\n  \"lint-staged\": {\n    \"src/**/*.ts\": [\n      \"eslint --fix\",\n      \"prettier --write\",\n      \"tsc --noEmit\"\n    ]\n  },\n  \"devDependencies\": {},\n  \"dependencies\": {}\n}\n"
                },
                {
                  "type": "file",
                  "path": "src/server.ts",
                  "content": "import app from \"./app\";\nimport env from \"./configs/env\";\nimport { logger } from \"./utils/logger\";\nimport { configureGracefulShutdown } from \"./utils/shutdown\";\n\nconst port = env.PORT || 9000;\n\nconst server = app.listen(port, () => {\n  logger.info(`[server]: Server is running at http://localhost:${port}`);\n  logger.info(`[server]: Environment: ${env.NODE_ENV}`);\n  logger.info(\n    `[server]: Swagger docs are available at http://localhost:${port}/api/docs`\n  );\n});\n\nconfigureGracefulShutdown(server);\n"
                },
                {
                  "type": "file",
                  "path": "src/app.ts",
                  "content": "import express, { Express, Request, Response } from \"express\";\nimport cors from \"cors\";\nimport helmet from \"helmet\";\nimport cookieParser from \"cookie-parser\";\nimport morgan from \"morgan\";\nimport { notFoundHandler } from \"./middlewares/not-found-handler\";\nimport { errorHandler } from \"./middlewares/error-handler\";\nimport { setupSwagger } from \"./configs/swagger\";\nimport healthRoutes from \"./routes/health.routes\";\nimport env from \"./configs/env\";\nimport sourceMapSupport from \"source-map-support\";\nsourceMapSupport.install();\n\nconst app: Express = express();\n\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\napp.use(\n  cors({\n    origin: env.CORS_ORIGIN,\n    methods: [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"OPTIONS\"],\n    allowedHeaders: [\"Content-Type\", \"Authorization\", \"X-Requested-With\"],\n    credentials: true\n  })\n);\napp.use(helmet());\napp.use(cookieParser());\napp.use(morgan(env.NODE_ENV === \"development\" ? \"dev\" : \"combined\"));\n\n//? Swagger Setup\nsetupSwagger(app);\n\n//? Routes\napp.get(\"/\", (req: Request, res: Response) => {\n  res.redirect(\"/api/health\");\n});\n\napp.use(\"/api/health\", healthRoutes);\n\n// Not found handler (should be after routes)\napp.use(notFoundHandler);\n\n// Global error handler (should be last)\napp.use(errorHandler);\n\nexport default app;\n"
                },
                {
                  "type": "file",
                  "path": "src/utils/shutdown.ts",
                  "content": "import { Server } from \"http\";\nimport { logger } from \"./logger\";\n\nexport const configureGracefulShutdown = (server: Server) => {\n  const signals = [\"SIGTERM\", \"SIGINT\"];\n\n  signals.forEach(signal => {\n    process.on(signal, () => {\n      logger.info(`\\n${signal} signal received. Shutting down gracefully...`);\n\n      server.close(err => {\n        if (err) {\n          logger.error(err, \"Error during server close\");\n          process.exit(1);\n        }\n\n        logger.info(\"HTTP server closed.\");\n        process.exit(0);\n      });\n\n      // Force shutdown after 10 seconds\n      setTimeout(() => {\n        logger.error(\n          \"Could not close connections in time, forcefully shutting down\"\n        );\n        process.exit(1);\n      }, 10000);\n    });\n  });\n};\n"
                },
                {
                  "type": "file",
                  "path": "src/utils/logger.ts",
                  "content": "import pino from \"pino\";\nimport env from \"../configs/env\";\n\nexport const logger = pino({\n  level: env.LOG_LEVEL,\n  transport:\n    env.NODE_ENV !== \"production\"\n      ? {\n          target: \"pino-pretty\",\n          options: {\n            colorize: true,\n            translateTime: \"yyyy-mm-dd HH:MM:ss\",\n            ignore: \"pid,hostname\"\n          }\n        }\n      : undefined\n});\n"
                },
                {
                  "type": "file",
                  "path": "src/utils/async-handler.ts",
                  "content": "import { Request, Response, NextFunction } from \"express\";\n\nexport type AsyncRouteHandler = (\n  req: Request,\n  res: Response,\n  next: NextFunction\n) => Promise<unknown>;\n\nexport function AsyncHandler(fn: AsyncRouteHandler) {\n  return function (req: Request, res: Response, next: NextFunction) {\n    Promise.resolve()\n      .then(() => fn(req, res, next))\n      .catch(next);\n  };\n}\n"
                },
                {
                  "type": "file",
                  "path": "src/utils/api-response.ts",
                  "content": "import { STATUS_CODES, StatusCode } from \"../constants/status-codes\";\nimport type { Response } from \"express\";\n\ntype ApiResponseParams<T> = {\n  success: boolean;\n  message: string;\n  statusCode: StatusCode;\n  data?: T | null;\n  errors?: unknown;\n};\n\nexport class ApiResponse<T = unknown> {\n  public readonly success: boolean;\n  public readonly message: string;\n  public readonly statusCode: StatusCode;\n  public readonly data?: T | null;\n  public readonly errors?: unknown;\n\n  constructor({\n    success,\n    message,\n    statusCode,\n    data,\n    errors\n  }: ApiResponseParams<T>) {\n    this.success = success;\n    this.message = message;\n    this.statusCode = statusCode;\n    this.data = data;\n    this.errors = errors;\n  }\n\n  send(res: Response): Response {\n    return res.status(this.statusCode).json({\n      success: this.success,\n      message: this.message,\n      statusCode: this.statusCode,\n      ...(this.data !== undefined && { data: this.data }),\n      ...(this.errors !== undefined && { errors: this.errors })\n    });\n  }\n\n  static Success<T>(\n    res: Response,\n    message: string,\n    data?: T,\n    statusCode: StatusCode = STATUS_CODES.OK\n  ): Response {\n    return new ApiResponse<T>({\n      success: true,\n      message,\n      data,\n      statusCode\n    }).send(res);\n  }\n\n  static ok<T>(res: Response, message = \"OK\", data?: T) {\n    return ApiResponse.Success(res, message, data, STATUS_CODES.OK);\n  }\n\n  static created<T>(res: Response, message = \"Created\", data?: T) {\n    return ApiResponse.Success(res, message, data, STATUS_CODES.CREATED);\n  }\n}\n\n/*\n * Usage:\n * ApiResponse.ok(res, \"OK\", data);\n * ApiResponse.created(res, \"Created\", data);\n */\n"
                },
                {
                  "type": "file",
                  "path": "src/utils/api-error.ts",
                  "content": "import { STATUS_CODES, StatusCode } from \"../constants/status-codes\";\n\nexport class ApiError extends Error {\n  public readonly statusCode: StatusCode;\n  public readonly isOperational: boolean;\n  public readonly errors?: unknown;\n\n  constructor(\n    statusCode: StatusCode,\n    message: string,\n    errors?: unknown,\n    isOperational = true\n  ) {\n    super(message);\n    this.name = \"ApiError\";\n    this.statusCode = statusCode;\n    this.errors = errors;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this, this.constructor);\n  }\n\n  static badRequest(message = \"Bad Request\", errors?: unknown) {\n    return new ApiError(STATUS_CODES.BAD_REQUEST, message, errors);\n  }\n\n  static unauthorized(message = \"Unauthorized\") {\n    return new ApiError(STATUS_CODES.UNAUTHORIZED, message);\n  }\n\n  static forbidden(message = \"Forbidden\") {\n    return new ApiError(STATUS_CODES.FORBIDDEN, message);\n  }\n\n  static notFound(message = \"Not Found\") {\n    return new ApiError(STATUS_CODES.NOT_FOUND, message);\n  }\n\n  static conflict(message = \"Conflict\") {\n    return new ApiError(STATUS_CODES.CONFLICT, message);\n  }\n\n  static validation(message = \"Validation failed\", errors?: unknown) {\n    return new ApiError(STATUS_CODES.BAD_REQUEST, message, errors);\n  }\n\n  static notImplemented(message = \"Not Implemented\") {\n    return new ApiError(STATUS_CODES.NOT_IMPLEMENTED, message);\n  }\n\n  static badGateway(message = \"Bad Gateway\") {\n    return new ApiError(STATUS_CODES.BAD_GATEWAY, message);\n  }\n\n  static serviceUnavailable(message = \"Service Unavailable\") {\n    return new ApiError(STATUS_CODES.SERVICE_UNAVAILABLE, message);\n  }\n\n  static tooManyRequests(message = \"Too Many Requests\") {\n    return new ApiError(STATUS_CODES.TOO_MANY_REQUESTS, message);\n  }\n\n  static server(message = \"Internal Server Error\") {\n    return new ApiError(STATUS_CODES.INTERNAL_SERVER_ERROR, message);\n  }\n}\n\n/*\n * Usage:\n * throw new ApiError(STATUS_CODES.NOT_FOUND, \"Not found\");\n * throw ApiError.badRequest(\"Bad request\");\n */\n"
                },
                {
                  "type": "file",
                  "path": "src/routes/health.routes.ts",
                  "content": "import { Router } from \"express\";\nimport {\n  healthCheck,\n  detailedHealthCheck\n} from \"../controllers/health.controller\";\n\nconst router = Router();\n\nrouter.get(\"/\", healthCheck);\nrouter.get(\"/detailed\", detailedHealthCheck);\n\nexport default router;\n"
                },
                {
                  "type": "file",
                  "path": "src/docs/swagger.json",
                  "content": "{}\n"
                },
                {
                  "type": "file",
                  "path": "src/controllers/health.controller.ts",
                  "content": "import { Request, Response } from \"express\";\nimport { ApiResponse } from \"../utils/api-response\";\nimport { AsyncHandler } from \"../utils/async-handler\";\n\n/**\n * Basic health check endpoint\n * GET /api/health\n */\nexport const healthCheck = AsyncHandler(\n  async (_req: Request, res: Response) => {\n    return ApiResponse.Success(res, \"Service is healthy\", {\n      status: \"healthy\",\n      timestamp: new Date().toISOString(),\n      uptime: process.uptime()\n    });\n  }\n);\n\n/**\n * Detailed health check with system information\n * GET /api/health/detailed\n */\nexport const detailedHealthCheck = AsyncHandler(\n  async (_req: Request, res: Response) => {\n    const healthData = {\n      status: \"healthy\",\n      timestamp: new Date().toISOString(),\n      uptime: process.uptime(),\n      environment: process.env.NODE_ENV || \"development\",\n      version: process.env.npm_package_version || \"1.0.0\",\n      memory: {\n        used:\n          Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) /\n          100,\n        total:\n          Math.round((process.memoryUsage().heapTotal / 1024 / 1024) * 100) /\n          100,\n        unit: \"MB\"\n      },\n      cpu: {\n        usage: process.cpuUsage()\n      }\n    };\n\n    return ApiResponse.Success(res, \"Service is healthy\", healthData);\n  }\n);\n"
                },
                {
                  "type": "file",
                  "path": "src/middlewares/not-found-handler.ts",
                  "content": "import { Request, Response, NextFunction } from \"express\";\nimport { ApiError } from \"../utils/api-error\";\n\nexport const notFoundHandler = (\n  req: Request,\n  res: Response,\n  next: NextFunction\n) => {\n  throw ApiError.notFound(`Route ${req.method} ${req.originalUrl} not found`);\n};\n"
                },
                {
                  "type": "file",
                  "path": "src/middlewares/error-handler.ts",
                  "content": "import { Request, Response, NextFunction } from \"express\";\nimport env from \"../configs/env\";\n\nimport { ApiError } from \"../utils/api-error\";\nimport { logger } from \"../utils/logger\";\n\nexport const errorHandler = (\n  err: Error,\n  req: Request,\n  res: Response,\n  next: NextFunction\n) => {\n  if (res.headersSent) {\n    return next(err);\n  }\n  let statusCode = 500;\n  let message = \"Internal server error\";\n  let errors: unknown;\n  if (err instanceof ApiError) {\n    statusCode = err.statusCode;\n    message = err.message;\n    errors = err.errors;\n  }\n\n  logger.error(\n    err,\n    `Error: ${message} | Status: ${statusCode} | Path: ${req.method} ${req.originalUrl}`\n  );\n\n  const response = {\n    success: false,\n    message,\n    statusCode,\n    ...(errors !== undefined && { errors }),\n    ...(env.NODE_ENV === \"development\" && { stack: err.stack })\n  };\n\n  res.status(statusCode).json(response);\n};\n"
                },
                {
                  "type": "file",
                  "path": "src/constants/status-codes.ts",
                  "content": "export const STATUS_CODES = {\n  // 2xx Success\n  OK: 200,\n  CREATED: 201,\n  ACCEPTED: 202,\n  NO_CONTENT: 204,\n\n  // 3xx Redirection\n  MOVED_PERMANENTLY: 301,\n  FOUND: 302,\n  NOT_MODIFIED: 304,\n\n  // 4xx Client Errors\n  BAD_REQUEST: 400,\n  UNAUTHORIZED: 401,\n  FORBIDDEN: 403,\n  NOT_FOUND: 404,\n  CONFLICT: 409,\n  UNPROCESSABLE_ENTITY: 422,\n  TOO_MANY_REQUESTS: 429,\n\n  // 5xx Server Errors\n  INTERNAL_SERVER_ERROR: 500,\n  NOT_IMPLEMENTED: 501,\n  BAD_GATEWAY: 502,\n  SERVICE_UNAVAILABLE: 503,\n  GATEWAY_TIMEOUT: 504\n} as const;\n\nexport type StatusCode = (typeof STATUS_CODES)[keyof typeof STATUS_CODES];\n"
                },
                {
                  "type": "file",
                  "path": "src/configs/swagger.ts",
                  "content": "import swaggerUi from \"swagger-ui-express\";\nimport { Express } from \"express\";\nimport env from \"./env\";\n\nimport swaggerDocument from \"../docs/swagger.json\"; // Generated by swagger-autogen by running `npx tsx swagger.config.ts`\n\nexport const setupSwagger = (app: Express) => {\n  if (env.NODE_ENV !== \"development\") return;\n\n  app.use(\"/api/docs\", swaggerUi.serve, swaggerUi.setup(swaggerDocument));\n};\n"
                },
                {
                  "type": "file",
                  "path": "src/configs/env.ts",
                  "content": "import \"dotenv-flow/config\";\nimport { z } from \"zod\";\n\nexport const envSchema = z.object({\n  NODE_ENV: z\n    .enum([\"development\", \"test\", \"production\"])\n    .default(\"development\"),\n\n  PORT: z.string().regex(/^\\d+$/, \"PORT must be a number\").transform(Number),\n\n  LOG_LEVEL: z\n    .enum([\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\"])\n    .default(\"info\"),\n\n  CORS_ORIGIN: z.url()\n});\n\nexport type Env = z.infer<typeof envSchema>;\n\nconst result = envSchema.safeParse(process.env);\n\nif (!result.success) {\n  console.error(\"❌ Invalid environment configuration\");\n  console.error(z.prettifyError(result.error));\n  process.exit(1);\n}\n\nexport const env: Readonly<Env> = Object.freeze(result.data);\n\nexport default env;\n"
                }
              ]
            },
            "feature": {
              "files": [
                {
                  "type": "file",
                  "path": "swagger.config.ts",
                  "content": "import swaggerAutoGen from \"swagger-autogen\";\n\nconst doc = {\n  info: {\n    title: \"Express Starter\",\n    description: \"Express Starter\",\n    version: \"1.0.0\"\n  },\n  host: `localhost:3000`,\n  schemes: [\"http\"]\n};\n\nconst outputFile = \"./src/docs/swagger.json\";\nconst endpointsFiles = [\"./src/routes/*.ts\"];\n\nswaggerAutoGen(outputFile, endpointsFiles, doc);\n"
                },
                {
                  "type": "file",
                  "path": "package.json",
                  "content": "{\n  \"name\": \"my-express-app\",\n  \"version\": \"1.0.0\",\n  \"main\": \"dist/server.js\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"cross-env NODE_ENV=development npx tsx watch src/server.ts\",\n    \"build\": \"rm -rf dist && tsc && tsc-alias\",\n    \"start\": \"cross-env NODE_ENV=production node dist/server.js\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"lint:check\": \"eslint .\",\n    \"lint:fix\": \"eslint . --fix\",\n    \"format:check\": \"npx prettier . --check\",\n    \"format:fix\": \"npx prettier . --write\",\n    \"docs\": \"npx tsx swagger.config.ts\"\n  },\n  \"lint-staged\": {\n    \"src/**/*.ts\": [\n      \"eslint --fix\",\n      \"prettier --write\",\n      \"tsc --noEmit\"\n    ]\n  },\n  \"devDependencies\": {},\n  \"dependencies\": {}\n}\n"
                },
                {
                  "type": "file",
                  "path": "src/server.ts",
                  "content": "import app from \"./app\";\nimport env from \"./shared/configs/env\";\nimport { logger } from \"./shared/utils/logger\";\nimport { configureGracefulShutdown } from \"./shared/utils/shutdown\";\n\nconst port = env.PORT || 9000;\n\nconst server = app.listen(port, () => {\n  logger.info(`[server]: Server is running at http://localhost:${port}`);\n  logger.info(`[server]: Environment: ${env.NODE_ENV}`);\n  logger.info(\n    `[server]: Swagger docs are available at http://localhost:${port}/api/docs`\n  );\n});\n\nconfigureGracefulShutdown(server);\n"
                },
                {
                  "type": "file",
                  "path": "src/app.ts",
                  "content": "import express, { Express, Request, Response } from \"express\";\nimport \"dotenv/config\";\nimport cors from \"cors\";\nimport helmet from \"helmet\";\nimport cookieParser from \"cookie-parser\";\nimport morgan from \"morgan\";\nimport sourceMapSupport from \"source-map-support\";\nsourceMapSupport.install();\n\nimport Routes from \"./routes/index\";\n\nimport { errorHandler } from \"./shared/middlewares/error-handler\";\nimport { notFoundHandler } from \"./shared/middlewares/not-found-handler\";\nimport { setupSwagger } from \"./shared/configs/swagger\";\nimport env from \"./shared/configs/env\";\n\nconst app: Express = express();\n\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\napp.use(\n  cors({\n    origin: env.CORS_ORIGIN,\n    methods: [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"OPTIONS\"],\n    allowedHeaders: [\"Content-Type\", \"Authorization\", \"X-Requested-With\"],\n    credentials: true\n  })\n);\napp.use(helmet());\napp.use(cookieParser());\napp.use(morgan(env.NODE_ENV === \"development\" ? \"dev\" : \"combined\"));\n\n//? Swagger Setup\nsetupSwagger(app);\n\n//? Routes\napp.get(\"/\", (req: Request, res: Response) => {\n  res.redirect(\"/api/health\");\n});\n\napp.use(\"/api\", Routes);\n\n// Not found handler (should be after routes)\napp.use(notFoundHandler);\n\n// Global error handler (should be last)\napp.use(errorHandler);\n\nexport default app;\n"
                },
                {
                  "type": "file",
                  "path": "src/routes/index.ts",
                  "content": "import { Router } from \"express\";\nimport HealthRouter from \"../modules/health/health.routes\";\n\nconst router = Router();\n\nrouter.use(\"/health\", HealthRouter);\n\nexport default router;\n"
                },
                {
                  "type": "file",
                  "path": "src/docs/swagger.json",
                  "content": "[]\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/utils/shutdown.ts",
                  "content": "import { Server } from \"http\";\nimport { logger } from \"./logger\";\n\nexport const configureGracefulShutdown = (server: Server) => {\n  const signals = [\"SIGTERM\", \"SIGINT\"];\n\n  signals.forEach(signal => {\n    process.on(signal, () => {\n      logger.info(`\\n${signal} signal received. Shutting down gracefully...`);\n\n      server.close(err => {\n        if (err) {\n          logger.error(err, \"Error during server close\");\n          process.exit(1);\n        }\n\n        logger.info(\"HTTP server closed.\");\n        process.exit(0);\n      });\n\n      // Force shutdown after 10 seconds\n      setTimeout(() => {\n        logger.error(\n          \"Could not close connections in time, forcefully shutting down\"\n        );\n        process.exit(1);\n      }, 10000);\n    });\n  });\n};\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/utils/logger.ts",
                  "content": "import pino from \"pino\";\nimport env from \"../../shared/configs/env\";\n\nexport const logger = pino({\n  level: env.LOG_LEVEL,\n  transport:\n    env.NODE_ENV !== \"production\"\n      ? {\n          target: \"pino-pretty\",\n          options: {\n            colorize: true,\n            translateTime: \"yyyy-mm-dd HH:MM:ss\",\n            ignore: \"pid,hostname\"\n          }\n        }\n      : undefined\n});\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/utils/async-handler.ts",
                  "content": "import { Request, Response, NextFunction } from \"express\";\n\nexport type AsyncRouteHandler = (\n  req: Request,\n  res: Response,\n  next: NextFunction\n) => Promise<unknown>;\n\nexport function AsyncHandler(fn: AsyncRouteHandler) {\n  return function (req: Request, res: Response, next: NextFunction) {\n    Promise.resolve()\n      .then(() => fn(req, res, next))\n      .catch(next);\n  };\n}\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/utils/api-response.ts",
                  "content": "import { STATUS_CODES, StatusCode } from \"../constants/status-codes\";\nimport type { Response } from \"express\";\n\ntype ApiResponseParams<T> = {\n  success: boolean;\n  message: string;\n  statusCode: StatusCode;\n  data?: T | null;\n  errors?: unknown;\n};\n\nexport class ApiResponse<T = unknown> {\n  public readonly success: boolean;\n  public readonly message: string;\n  public readonly statusCode: StatusCode;\n  public readonly data?: T | null;\n  public readonly errors?: unknown;\n\n  constructor({\n    success,\n    message,\n    statusCode,\n    data,\n    errors\n  }: ApiResponseParams<T>) {\n    this.success = success;\n    this.message = message;\n    this.statusCode = statusCode;\n    this.data = data;\n    this.errors = errors;\n  }\n\n  send(res: Response): Response {\n    return res.status(this.statusCode).json({\n      success: this.success,\n      message: this.message,\n      statusCode: this.statusCode,\n      ...(this.data !== undefined && { data: this.data }),\n      ...(this.errors !== undefined && { errors: this.errors })\n    });\n  }\n\n  static Success<T>(\n    res: Response,\n    message: string,\n    data?: T,\n    statusCode: StatusCode = STATUS_CODES.OK\n  ): Response {\n    return new ApiResponse<T>({\n      success: true,\n      message,\n      data,\n      statusCode\n    }).send(res);\n  }\n\n  static ok<T>(res: Response, message = \"OK\", data?: T) {\n    return ApiResponse.Success(res, message, data, STATUS_CODES.OK);\n  }\n\n  static created<T>(res: Response, message = \"Created\", data?: T) {\n    return ApiResponse.Success(res, message, data, STATUS_CODES.CREATED);\n  }\n}\n\n/*\n * Usage:\n * ApiResponse.ok(res, \"OK\", data);\n * ApiResponse.created(res, \"Created\", data);\n */\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/constants/status-codes.ts",
                  "content": "export const STATUS_CODES = {\n  // 2xx Success\n  OK: 200,\n  CREATED: 201,\n  ACCEPTED: 202,\n  NO_CONTENT: 204,\n\n  // 3xx Redirection\n  MOVED_PERMANENTLY: 301,\n  FOUND: 302,\n  NOT_MODIFIED: 304,\n\n  // 4xx Client Errors\n  BAD_REQUEST: 400,\n  UNAUTHORIZED: 401,\n  FORBIDDEN: 403,\n  NOT_FOUND: 404,\n  CONFLICT: 409,\n  UNPROCESSABLE_ENTITY: 422,\n  TOO_MANY_REQUESTS: 429,\n\n  // 5xx Server Errors\n  INTERNAL_SERVER_ERROR: 500,\n  NOT_IMPLEMENTED: 501,\n  BAD_GATEWAY: 502,\n  SERVICE_UNAVAILABLE: 503,\n  GATEWAY_TIMEOUT: 504\n} as const;\n\nexport type StatusCode = (typeof STATUS_CODES)[keyof typeof STATUS_CODES];\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/errors/api-error.ts",
                  "content": "import { STATUS_CODES, StatusCode } from \"../constants/status-codes\";\n\nexport class ApiError extends Error {\n  public readonly statusCode: StatusCode;\n  public readonly isOperational: boolean;\n  public readonly errors?: unknown;\n\n  constructor(\n    statusCode: StatusCode,\n    message: string,\n    errors?: unknown,\n    isOperational = true\n  ) {\n    super(message);\n    this.name = \"ApiError\";\n    this.statusCode = statusCode;\n    this.errors = errors;\n    this.isOperational = isOperational;\n\n    Error.captureStackTrace(this, this.constructor);\n  }\n\n  static badRequest(message = \"Bad Request\", errors?: unknown) {\n    return new ApiError(STATUS_CODES.BAD_REQUEST, message, errors);\n  }\n\n  static unauthorized(message = \"Unauthorized\") {\n    return new ApiError(STATUS_CODES.UNAUTHORIZED, message);\n  }\n\n  static forbidden(message = \"Forbidden\") {\n    return new ApiError(STATUS_CODES.FORBIDDEN, message);\n  }\n\n  static notFound(message = \"Not Found\") {\n    return new ApiError(STATUS_CODES.NOT_FOUND, message);\n  }\n\n  static conflict(message = \"Conflict\") {\n    return new ApiError(STATUS_CODES.CONFLICT, message);\n  }\n\n  static validation(message = \"Validation failed\", errors?: unknown) {\n    return new ApiError(STATUS_CODES.BAD_REQUEST, message, errors);\n  }\n\n  static notImplemented(message = \"Not Implemented\") {\n    return new ApiError(STATUS_CODES.NOT_IMPLEMENTED, message);\n  }\n\n  static badGateway(message = \"Bad Gateway\") {\n    return new ApiError(STATUS_CODES.BAD_GATEWAY, message);\n  }\n\n  static serviceUnavailable(message = \"Service Unavailable\") {\n    return new ApiError(STATUS_CODES.SERVICE_UNAVAILABLE, message);\n  }\n\n  static tooManyRequests(message = \"Too Many Requests\") {\n    return new ApiError(STATUS_CODES.TOO_MANY_REQUESTS, message);\n  }\n\n  static server(message = \"Internal Server Error\") {\n    return new ApiError(STATUS_CODES.INTERNAL_SERVER_ERROR, message);\n  }\n}\n\n/*\n * Usage:\n * throw new ApiError(STATUS_CODES.NOT_FOUND, \"Not found\");\n * throw ApiError.badRequest(\"Bad request\");\n */\n"
                },
                {
                  "type": "file",
                  "path": "src/modules/health/health.routes.ts",
                  "content": "import { Router } from \"express\";\nimport { healthCheck, detailedHealthCheck } from \"./health.controller\";\n\nconst router = Router();\n\nrouter.get(\"/\", healthCheck);\nrouter.get(\"/detailed\", detailedHealthCheck);\n\nexport default router;\n"
                },
                {
                  "type": "file",
                  "path": "src/modules/health/health.controller.ts",
                  "content": "import { Request, Response } from \"express\";\nimport { ApiResponse } from \"../../shared/utils/api-response\";\nimport { AsyncHandler } from \"../../shared/utils/async-handler\";\n\n/**\n * Basic health check endpoint\n * GET /api/health\n */\nexport const healthCheck = AsyncHandler(\n  async (_req: Request, res: Response) => {\n    return ApiResponse.Success(res, \"Service is healthy\", {\n      status: \"healthy\",\n      timestamp: new Date().toISOString(),\n      uptime: process.uptime()\n    });\n  }\n);\n\n/**\n * Detailed health check with system information\n * GET /api/health/detailed\n */\nexport const detailedHealthCheck = AsyncHandler(\n  async (_req: Request, res: Response) => {\n    const healthData = {\n      status: \"healthy\",\n      timestamp: new Date().toISOString(),\n      uptime: process.uptime(),\n      environment: process.env.NODE_ENV || \"development\",\n      version: process.env.npm_package_version || \"1.0.0\",\n      memory: {\n        used:\n          Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) /\n          100,\n        total:\n          Math.round((process.memoryUsage().heapTotal / 1024 / 1024) * 100) /\n          100,\n        unit: \"MB\"\n      },\n      cpu: {\n        usage: process.cpuUsage()\n      }\n    };\n\n    return ApiResponse.Success(res, \"Service is healthy\", healthData);\n  }\n);\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/middlewares/not-found-handler.ts",
                  "content": "import { Request, Response, NextFunction } from \"express\";\nimport { ApiError } from \"../errors/api-error\";\n\nexport const notFoundHandler = (\n  req: Request,\n  res: Response,\n  next: NextFunction\n) => {\n  throw ApiError.notFound(`Route ${req.method} ${req.originalUrl} not found`);\n};\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/middlewares/error-handler.ts",
                  "content": "import { Request, Response, NextFunction } from \"express\";\nimport env from \"../configs/env\";\n\nimport { logger } from \"../utils/logger\";\nimport { ApiError } from \"../errors/api-error\";\n\nexport const errorHandler = (\n  err: Error,\n  req: Request,\n  res: Response,\n  next: NextFunction\n) => {\n  if (res.headersSent) {\n    return next(err);\n  }\n  let statusCode = 500;\n  let message = \"Internal server error\";\n  let errors: unknown;\n\n  if (err instanceof ApiError) {\n    statusCode = err.statusCode;\n    message = err.message;\n    errors = err.errors;\n  }\n\n  logger.error(\n    err,\n    `Error: ${message} | Status: ${statusCode} | Path: ${req.method} ${req.originalUrl}`\n  );\n\n  const response = {\n    success: false,\n    message,\n    statusCode,\n    ...(errors !== undefined && { errors }),\n    ...(env.NODE_ENV === \"development\" && { stack: err.stack })\n  };\n\n  res.status(statusCode).json(response);\n};\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/configs/swagger.ts",
                  "content": "import swaggerUi from \"swagger-ui-express\";\nimport { Express } from \"express\";\nimport env from \"./env\";\n\nimport swaggerDocument from \"../../docs/swagger.json\";\n\nexport const setupSwagger = (app: Express) => {\n  if (env.NODE_ENV !== \"development\") return;\n  app.use(\"/api/docs\", swaggerUi.serve, swaggerUi.setup(swaggerDocument));\n};\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/configs/env.ts",
                  "content": "import \"dotenv-flow/config\";\nimport { z } from \"zod\";\n\nexport const envSchema = z.object({\n  NODE_ENV: z\n    .enum([\"development\", \"test\", \"production\"])\n    .default(\"development\"),\n\n  PORT: z.string().regex(/^\\d+$/, \"PORT must be a number\").transform(Number),\n\n  DATABASE_URL: z.url(),\n\n  LOG_LEVEL: z\n    .enum([\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\"])\n    .default(\"info\"),\n\n  CORS_ORIGIN: z.string()\n});\n\nexport type Env = z.infer<typeof envSchema>;\n\nconst result = envSchema.safeParse(process.env);\n\nif (!result.success) {\n  console.error(\"❌ Invalid environment configuration\");\n  console.error(z.prettifyError(result.error));\n  process.exit(1);\n}\n\nexport const env: Readonly<Env> = Object.freeze(result.data);\n\nexport default env;\n"
                }
              ]
            }
          }
        }
      }
    }
  }
}
