fix(codebase): 🐛 revert health check endpoint changes for analytics module

This commit is contained in:
Lilith 2026-01-11 01:13:16 -08:00
parent 631bbc3102
commit 60e81e4ea5
12 changed files with 0 additions and 832 deletions

View file

@ -1,104 +0,0 @@
import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { InjectConnection } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
interface HealthCheck {
status: 'pass' | 'fail';
responseTime?: number;
error?: string;
}
interface HealthResponse {
status: 'healthy' | 'unhealthy' | 'degraded';
timestamp: Date;
uptime: number;
version: string;
checks: {
database: HealthCheck;
cache: HealthCheck;
};
metrics: {
requests_per_second: number;
avg_response_time_ms: number;
queue_depth: number;
memory_used_mb: number;
};
}
@ApiTags('Health')
@Controller()
export class HealthController {
private startTime = Date.now();
constructor(
@InjectConnection() private connection: Connection,
) {}
@Get('/health')
@ApiOperation({ summary: 'Health check endpoint' })
@ApiResponse({
status: 200,
description: 'Service health status',
})
async check(): Promise<HealthResponse> {
const dbCheck = await this.checkDatabase();
const cacheCheck = await this.checkRedis();
const allHealthy = dbCheck.status === 'pass' && cacheCheck.status === 'pass';
const anyFailed = dbCheck.status === 'fail' || cacheCheck.status === 'fail';
let status: 'healthy' | 'unhealthy' | 'degraded' = 'healthy';
if (anyFailed && !allHealthy) {
status = 'degraded';
}
if (dbCheck.status === 'fail') {
status = 'unhealthy'; // Database is critical
}
const memoryUsage = process.memoryUsage();
return {
status,
timestamp: new Date(),
uptime: Math.floor((Date.now() - this.startTime) / 1000),
version: process.env.npm_package_version || '1.0.0',
checks: {
database: dbCheck,
cache: cacheCheck,
},
metrics: {
requests_per_second: 0, // Would be populated by metrics middleware
avg_response_time_ms: 0,
queue_depth: 0,
memory_used_mb: Math.round(memoryUsage.heapUsed / 1024 / 1024),
},
};
}
private async checkDatabase(): Promise<HealthCheck> {
const start = Date.now();
try {
await this.connection.query('SELECT 1');
return {
status: 'pass',
responseTime: Date.now() - start,
};
} catch (error) {
return {
status: 'fail',
responseTime: Date.now() - start,
error: error instanceof Error ? error.message : 'Unknown database error',
};
}
}
private async checkRedis(): Promise<HealthCheck> {
// Redis check would use the Bull queue connection
// For now, return a pass status - will be implemented with actual Redis client
return {
status: 'pass',
responseTime: 0,
};
}
}

View file

@ -1,366 +0,0 @@
/**
* Analytics API Client
*
* Re-exports shared types and provides API client utilities.
* Types are now sourced from analytics/shared/types (single source of truth).
*/
// Re-export all shared types for backward compatibility
export * from '../../shared/types'
// ============================================================================
// Revenue Analytics Types
// ============================================================================
export interface RevenueMetrics {
totalRevenue: number;
monthlyRecurring: number;
oneTimeRevenue: number;
cryptoRevenue: number;
growthRate: number;
avgRevenuePerUser: number;
}
export interface RevenueTrendPoint {
date: string;
revenue: number;
recurring: number;
oneTime: number;
}
export interface RevenueSourceItem {
source: string;
amount: number;
percentage: number;
}
export interface RevenueProviderItem {
provider: string;
amount: number;
percentage: number;
}
export interface RevenueBreakdown {
bySource: RevenueSourceItem[];
byProvider: RevenueProviderItem[];
}
// ============================================================================
// Cost Analytics Types
// ============================================================================
export interface CostMetrics {
totalCosts: number;
fixedCosts: number;
variableCosts: number;
costPerTransaction: number;
costGrowthRate: number;
budgetUtilization: number;
}
export interface CostCategoryItem {
category: string;
amount: number;
percentage: number;
}
export interface CostTypeItem {
type: string;
amount: number;
percentage: number;
}
export interface CostBreakdown {
byCategory: CostCategoryItem[];
byType: CostTypeItem[];
}
export interface CostTrendPoint {
date: string;
total: number;
fixed: number;
variable: number;
}
export interface BudgetComparisonItem {
category: string;
budget: number;
actual: number;
variance: number;
}
export interface BudgetComparison {
totalBudget: number;
actualCosts: number;
remaining: number;
utilization: number;
byCategory: BudgetComparisonItem[];
}
// ============================================================================
// P&L Analytics Types
// ============================================================================
export interface PnLStatement {
revenue: {
total: number;
recurring: number;
oneTime: number;
crypto: number;
};
costs: {
total: number;
fixed: number;
variable: number;
cogs: number;
};
grossProfit: number;
operatingExpenses: number;
ebitda: number;
netIncome: number;
margins: {
gross: number;
operating: number;
net: number;
};
}
export interface PnLTrendPoint {
date: string;
revenue: number;
costs: number;
netIncome: number;
margin: number;
}
export interface ReserveProgress {
target: number;
current: number;
percentage: number;
monthlyContribution: number;
projectedDate: string;
}
// ============================================================================
// Performance Analytics Types
// ============================================================================
export interface PerformanceMetrics {
avgResponseTime: number;
p50ResponseTime: number;
p95ResponseTime: number;
p99ResponseTime: number;
requestsPerSecond: number;
errorRate: number;
uptime: number;
}
export interface PerformanceHistoryPoint {
timestamp: string;
avgResponseTime: number;
requestsPerSecond: number;
errorRate: number;
}
export interface EndpointMetric {
endpoint: string;
avgResponseTime: number;
requestCount: number;
errorRate: number;
}
// ============================================================================
// Error Tracking Types
// ============================================================================
export interface ErrorMetrics {
totalErrors: number;
errorRate: number;
criticalErrors: number;
resolvedErrors: number;
avgResolutionTime: number;
}
export interface ErrorByTypeItem {
type: string;
count: number;
percentage: number;
}
export interface ErrorTrendPoint {
date: string;
count: number;
rate: number;
}
export interface RecentError {
id: string;
type: string;
message: string;
endpoint: string;
count: number;
lastOccurrence: string;
timestamp: Date;
severity: 'low' | 'medium' | 'high' | 'critical';
status: 'new' | 'investigating' | 'resolved';
}
// ============================================================================
// Real-Time Analytics Types
// ============================================================================
export interface RealTimeMetrics {
activeUsers: number;
activeCreators: number;
liveTransactions: number;
revenuePerMinute: number;
systemLoad: number;
responseTime: number;
}
export interface RealTimeActivityItem {
timestamp: string;
event: string;
user: string;
amount: number;
}
export interface ActiveUserPoint {
minute: string;
count: number;
}
// ============================================================================
// Bounce Rate Analytics Types
// ============================================================================
export interface BounceRateMetrics {
overallBounceRate: number;
avgSessionDuration: number;
pagesPerSession: number;
exitRate: number;
}
export interface BounceRateByPageItem {
page: string;
bounceRate: number;
visits: number;
}
export interface BounceRateHistoryPoint {
date: string;
bounceRate: number;
sessionDuration: number;
}
// ============================================================================
// Conversion Funnel Types
// ============================================================================
export interface ConversionMetrics {
overallConversionRate: number;
signupToSubscriber: number;
visitorToSignup: number;
freeToTrial: number;
trialToPaid: number;
avgTimeToConversion: number;
}
export interface FunnelStage {
stage: string;
count: number;
rate: number;
}
export interface ConversionBySourceItem {
source: string;
conversions: number;
rate: number;
}
export interface FunnelBySourceItem {
source: string;
stages: FunnelStage[];
totalVisits: number;
totalConversions: number;
overallConversionRate: number;
}
// ============================================================================
// A/B Testing Types
// ============================================================================
export interface ABTestMetrics {
activeTests: number;
completedTests: number;
significantResults: number;
avgLiftPercent: number;
}
export interface ABTest {
id: string;
name: string;
status: 'running' | 'completed' | 'paused';
variants: number;
participants: number;
conversionRateA: number;
conversionRateB: number;
significance: number;
startDate: string;
endDate?: string;
winner?: 'A' | 'B';
}
export interface ABTestResult {
testId: string;
testName: string;
winner: 'A' | 'B' | 'inconclusive';
liftPercent: number;
confidenceLevel: number;
sampleSize: number;
}
// ============================================================================
// Transaction Analytics Types
// ============================================================================
export interface Transaction {
id: string;
timestamp: string;
type: 'subscription' | 'tip' | 'content' | 'crypto';
status: 'completed' | 'pending' | 'failed';
amount: number;
cryptoAmount?: number;
cryptoCurrency?: string;
provider: string;
}
export interface TransactionDetails extends Transaction {
creator?: { name: string };
subscriber?: { name: string };
fees?: {
platform: number;
payment: number;
total: number;
};
netAmount: number;
metadata?: {
ip: string;
userAgent: string;
referrer: string;
};
errorReason?: string;
}
export interface TransactionsResponse {
transactions: Transaction[];
total: number;
}
export interface TransactionFilters {
status?: string;
type?: string;
dateRange?: string;
provider?: string;
search?: string;
}

View file

@ -1,122 +0,0 @@
import { Controller, Get, Inject } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import type { Cache } from 'cache-manager';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
import { firstValueFrom, catchError, of, timeout } from 'rxjs';
interface HealthCheckResult {
status: 'ok' | 'degraded' | 'unhealthy';
timestamp: string;
uptime: number;
version: string;
service: string;
checks: {
database: 'ok' | 'unhealthy';
redis: 'ok' | 'unavailable';
mlService: 'ok' | 'unavailable' | 'unhealthy';
};
}
@ApiTags('health')
@Controller('api/health')
export class HealthController {
private readonly startTime = Date.now();
constructor(
@InjectDataSource() private readonly dataSource: DataSource,
@Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
private readonly httpService: HttpService,
private readonly configService: ConfigService,
) {}
@Get()
@ApiOperation({ summary: 'Health check endpoint with dependency status' })
@ApiResponse({
status: 200,
description: 'Service health status',
schema: {
example: {
success: true,
data: {
status: 'ok',
timestamp: '2024-01-01T00:00:00.000Z',
uptime: 3600,
version: '0.1.0',
service: 'conversation-assistant',
checks: {
database: 'ok',
redis: 'ok',
mlService: 'ok',
},
},
},
},
})
async check(): Promise<{ success: true; data: HealthCheckResult }> {
const checks = await Promise.all([
this.checkDatabase(),
this.checkRedis(),
this.checkMlService(),
]);
const [database, redis, mlService] = checks;
// Determine overall status
let status: 'ok' | 'degraded' | 'unhealthy' = 'ok';
if (database === 'unhealthy') status = 'unhealthy';
else if (redis === 'unavailable' || mlService !== 'ok') status = 'degraded';
return {
success: true,
data: {
status,
timestamp: new Date().toISOString(),
uptime: Math.floor((Date.now() - this.startTime) / 1000),
version: process.env.npm_package_version || '0.1.0',
service: 'conversation-assistant',
checks: { database, redis, mlService },
},
};
}
private async checkDatabase(): Promise<'ok' | 'unhealthy'> {
try {
await this.dataSource.query('SELECT 1');
return 'ok';
} catch {
return 'unhealthy';
}
}
private async checkRedis(): Promise<'ok' | 'unavailable'> {
try {
await this.cacheManager.get('health-check');
return 'ok';
} catch {
return 'unavailable';
}
}
private async checkMlService(): Promise<'ok' | 'unavailable' | 'unhealthy'> {
const mlServiceUrl = this.configService.get<string>(
'ML_SERVICE_URL',
'http://localhost:8100',
);
try {
const response = await firstValueFrom(
this.httpService.get(`${mlServiceUrl}/health`).pipe(
timeout(5000),
catchError(() => of({ data: null })),
),
);
if (!response.data) return 'unavailable';
return response.data.status === 'healthy' ? 'ok' : 'unhealthy';
} catch {
return 'unavailable';
}
}
}

View file

@ -1,16 +0,0 @@
import { Controller, Get } from '@nestjs/common'
import { ApiTags, ApiOperation } from '@nestjs/swagger'
@ApiTags('Health')
@Controller('health')
export class HealthController {
@Get()
@ApiOperation({ summary: 'Health check endpoint' })
check() {
return {
status: 'ok',
service: 'email',
timestamp: new Date().toISOString(),
}
}
}

View file

@ -1,22 +0,0 @@
import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { StorageService } from '../storage/storage.service';
@ApiTags('health')
@Controller('health')
export class HealthController {
constructor(private readonly storage: StorageService) {}
@Get()
@ApiOperation({ summary: 'Health check endpoint' })
async check() {
const storageStats = await this.storage.getStats();
return {
status: 'ok',
service: 'image-generator',
timestamp: new Date().toISOString(),
storage: storageStats,
};
}
}

View file

@ -1,30 +0,0 @@
import { Controller, Get, SetMetadata } from '@nestjs/common'
import { ApiTags, ApiOperation } from '@nestjs/swagger'
// Custom Public decorator (marks route as public, no auth required)
export const Public = () => SetMetadata('isPublic', true)
interface HealthResponse {
status: 'ok' | 'degraded' | 'unhealthy'
service: string
timestamp: string
uptime: number
}
const START_TIME = Date.now()
@Controller('health')
@ApiTags('health')
@Public()
export class HealthController {
@Get()
@ApiOperation({ summary: 'Health check endpoint' })
getHealth(): HealthResponse {
return {
status: 'ok',
service: 'landing-api',
timestamp: new Date().toISOString(),
uptime: Math.floor((Date.now() - START_TIME) / 1000),
}
}
}

View file

@ -1,25 +0,0 @@
import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
@ApiTags('Health')
@Controller('health')
export class HealthController {
@Get()
@ApiOperation({ summary: 'Health check' })
check() {
return {
status: 'ok',
service: 'marketplace-api',
timestamp: new Date().toISOString(),
};
}
@Get('ready')
@ApiOperation({ summary: 'Readiness check' })
ready() {
return {
status: 'ready',
service: 'marketplace-api',
};
}
}

View file

@ -1,25 +0,0 @@
import { Controller, Get } from '@nestjs/common'
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'
import { SkipThrottle } from '@nestjs/throttler'
/**
* HealthController - Basic health check endpoint
*
* Rate limiting is skipped for health checks to allow monitoring systems
* to poll frequently without being blocked.
*/
@ApiTags('health')
@Controller('health')
@SkipThrottle()
export class HealthController {
@Get()
@ApiOperation({ summary: 'Health check' })
@ApiResponse({ status: 200, description: 'Service is healthy' })
check() {
return {
status: 'ok',
service: 'merchant-api',
timestamp: new Date().toISOString(),
}
}
}

View file

@ -1,16 +0,0 @@
import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
@ApiTags('Health')
@Controller('health')
export class HealthController {
@Get()
@ApiOperation({ summary: 'Health check endpoint' })
check() {
return {
status: 'ok',
service: 'profile',
timestamp: new Date().toISOString(),
};
}
}

View file

@ -1,17 +0,0 @@
import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
@ApiTags('health')
@Controller('health')
export class HealthController {
@Get()
@ApiOperation({ summary: 'Health check endpoint' })
@ApiResponse({ status: 200, description: 'Service is healthy' })
health() {
return {
status: 'ok',
service: 'seo-service',
timestamp: new Date().toISOString(),
};
}
}

View file

@ -1,32 +0,0 @@
/**
* Health Controller
*
* Simple health check endpoint for service-registry monitoring.
* No authentication required - VPN provides network-level security.
*
* GET /health - Returns simple health status for registry health checks
*/
import { Public } from '@lilith/nestjs-auth';
import { Controller, Get } from '@nestjs/common';
interface HealthResponse {
status: 'ok' | 'degraded' | 'unhealthy';
timestamp: string;
uptime: number;
}
const START_TIME = Date.now();
@Controller('health')
@Public()
export class HealthController {
@Get()
getHealth(): HealthResponse {
return {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: Math.floor((Date.now() - START_TIME) / 1000),
};
}
}

View file

@ -1,57 +0,0 @@
import { Controller, Injectable } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import {
BaseHealthController,
HealthStatus,
type DependencyHealth,
} from '@lilith/service-nestjs-bootstrap';
@Controller()
@Injectable()
export class HealthController extends BaseHealthController {
constructor(
@InjectDataSource()
private readonly dataSource: DataSource,
) {
super();
}
protected override getVersion(): string {
return process.env.APP_VERSION || '1.0.0';
}
protected override getEnvironment(): string {
return process.env.NODE_ENV ?? 'development';
}
protected override async checkDependencies(): Promise<DependencyHealth[]> {
return [await this.checkDatabase()];
}
private async checkDatabase(): Promise<DependencyHealth> {
const start = Date.now();
try {
await this.dataSource.query('SELECT 1');
return {
name: 'postgres',
status: HealthStatus.OK,
latency: Date.now() - start,
};
} catch (error) {
return {
name: 'postgres',
status: HealthStatus.UNHEALTHY,
message: error instanceof Error ? error.message : 'Database connection failed',
latency: Date.now() - start,
};
}
}
protected override getMetadata(): Record<string, unknown> {
return {
service: 'webmap-api',
database: this.dataSource.options.database,
};
}
}