localgreenchain/pages/api/health/ready.ts
Claude 5ea8bab5c3
Add production deployment infrastructure (Agent 4)
- Docker: Multi-stage Dockerfile with security hardening, docker-compose
  for production and development environments
- Environment: Comprehensive .env.example with all config options,
  lib/config/env.ts for typed environment validation
- Logging: Structured JSON logging with request/response middleware
- Monitoring: Prometheus metrics endpoint, Grafana dashboard, health
  checks (liveness/readiness probes)
- Security: Security headers, rate limiting, CORS middleware
- CI/CD: GitHub Actions workflows for CI, production deploy, and
  preview deployments
- Error tracking: Sentry integration foundation

Files created:
- Docker: Dockerfile, docker-compose.yml, docker-compose.dev.yml, .dockerignore
- Config: lib/config/env.ts, lib/config/index.ts
- Logging: lib/logging/logger.ts, lib/logging/middleware.ts
- Monitoring: lib/monitoring/sentry.ts, lib/monitoring/metrics.ts,
  lib/monitoring/health.ts
- Security: lib/security/headers.ts, lib/security/rateLimit.ts,
  lib/security/cors.ts
- API: pages/api/health/*, pages/api/metrics.ts
- Infra: infra/prometheus/prometheus.yml, infra/grafana/*
2025-11-23 03:54:03 +00:00

65 lines
1.7 KiB
TypeScript

/**
* Readiness Probe Endpoint
* Agent 4: Production Deployment
*
* GET /api/health/ready
* Returns readiness status for Kubernetes/container orchestration.
* Used to determine if the application is ready to receive traffic.
*/
import type { NextApiRequest, NextApiResponse } from 'next';
import { healthChecks } from '../../../lib/monitoring';
interface ReadyResponse {
ready: boolean;
checks: Array<{
name: string;
status: string;
}>;
timestamp: string;
}
interface ErrorResponse {
ready: boolean;
error: string;
timestamp: string;
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<ReadyResponse | ErrorResponse>
) {
if (req.method !== 'GET') {
res.setHeader('Allow', ['GET']);
return res.status(405).json({
ready: false,
error: `Method ${req.method} is not allowed`,
timestamp: new Date().toISOString(),
});
}
try {
const health = await healthChecks.checkReadiness();
const isReady = health.status === 'healthy' || health.status === 'degraded';
// Add cache headers - don't cache readiness checks
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
return res.status(isReady ? 200 : 503).json({
ready: isReady,
checks: health.checks.map((c) => ({
name: c.name,
status: c.status,
})),
timestamp: health.timestamp,
});
} catch (error) {
return res.status(503).json({
ready: false,
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: new Date().toISOString(),
});
}
}