import { Router } from 'express'; import { neo4jService } from '../database/Neo4jService'; import { checkPrismaConnection, prisma } from '../database/prisma'; const router = Router(); /** * Overall system health check */ router.get('/health', async (req, res) => { const health = { status: 'healthy', timestamp: new Date().toISOString(), services: { database: 'unknown', neo4j: 'unknown', redis: 'unknown', }, uptime: process.uptime(), memory: process.memoryUsage(), }; try { // Check Prisma/PostgreSQL const prismaHealthy = await checkPrismaConnection(); health.services.database = prismaHealthy ? 'healthy' : 'unhealthy'; if (!prismaHealthy) health.status = 'degraded'; } catch { health.services.database = 'unhealthy'; health.status = 'degraded'; } try { // Check Neo4j await neo4jService.connect(); const neo4jHealthy = await neo4jService.healthCheck(); health.services.neo4j = neo4jHealthy ? 'healthy' : 'unhealthy'; await neo4jService.disconnect(); if (!neo4jHealthy) { health.status = 'degraded'; } } catch (error) { health.services.neo4j = 'unhealthy'; health.status = 'degraded'; } // Check Redis if (process.env.REDIS_URL) { // Redis URL is configured but ioredis client is not yet installed // Once ioredis is installed, this can be updated to perform actual health check health.services.redis = 'configured_but_client_unavailable'; } else { health.services.redis = 'not_configured'; } const statusCode = health.status === 'healthy' ? 200 : 503; res.status(statusCode).json(health); }); /** * Database-specific health check */ router.get('/health/database', async (req, res) => { try { const prismaHealthy = await checkPrismaConnection(); if (!prismaHealthy) { return res.status(503).json({ status: 'unhealthy', error: 'Prisma unreachable', }); } const result = await prisma.$queryRaw`SELECT 1 as test`; res.json({ status: 'healthy', type: 'PostgreSQL (Prisma)', tables: 'n/a', test: (result as any[])[0]?.test === 1, }); } catch (error) { res.status(503).json({ status: 'unhealthy', error: String(error), }); } }); /** * Neo4j-specific health check */ router.get('/health/neo4j', async (req, res) => { try { await neo4jService.connect(); const healthy = await neo4jService.healthCheck(); if (healthy) { const stats = await neo4jService.runQuery('MATCH (n) RETURN count(n) as nodeCount'); await neo4jService.disconnect(); res.json({ status: 'healthy', connected: true, nodeCount: stats[0]?.nodeCount || 0, }); } else { throw new Error('Health check failed'); } } catch (error) { res.status(503).json({ status: 'unhealthy', connected: false, error: String(error), }); } }); /** * Readiness check (for Kubernetes) */ router.get('/ready', async (req, res) => { try { // Use Prisma connection check instead of SQLite const prismaHealthy = await checkPrismaConnection(); if (!prismaHealthy) { throw new Error('Database not ready'); } res.json({ status: 'ready', timestamp: new Date().toISOString(), }); } catch (error) { res.status(503).json({ status: 'not_ready', error: String(error), }); } }); /** * Liveness check (for Kubernetes) */ router.get('/live', (req, res) => { res.json({ status: 'alive', timestamp: new Date().toISOString(), uptime: process.uptime(), }); }); export default router;