From 54762a85973f37adc74505b594e13f9eb4b4760c Mon Sep 17 00:00:00 2001 From: Ebuka321 Date: Tue, 28 Apr 2026 03:35:49 -0700 Subject: [PATCH 1/4] Implement missing performance monitoring system - Create comprehensive performance dashboard (service-overview.json) - Add database query performance monitoring (DatabaseMonitor.ts) - Add performance alerts to alert-rules.yml Closes #260 --- backend/observability/config/alert-rules.yml | 104 +++++ .../dashboards/service-overview.json | 370 ++++++++++++++++++ .../monitoring/DatabaseMonitor.ts | 204 ++++++++++ 3 files changed, 678 insertions(+) create mode 100644 backend/observability/monitoring/DatabaseMonitor.ts diff --git a/backend/observability/config/alert-rules.yml b/backend/observability/config/alert-rules.yml index 47c9f542..efc766d6 100644 --- a/backend/observability/config/alert-rules.yml +++ b/backend/observability/config/alert-rules.yml @@ -226,3 +226,107 @@ groups: annotations: summary: "Unusual error rate detected" description: "Error rate on {{ $labels.service }} deviates significantly from normal" + + - name: performance_alerts + interval: 30s + rules: + # High Memory Usage per Service + - alert: HighMemoryUsageService + expr: process_resident_memory_bytes{job=~"user-service|payment-service|billing-service|notification-service|document-service|utility-service|analytics-service|webhook-service"} / 1024 / 1024 / 1024 > 1 + for: 5m + labels: + severity: warning + category: performance + annotations: + summary: "High memory usage on {{ $labels.job }}" + description: "Memory usage is {{ $value | humanize }}GB on {{ $labels.job }}" + + # High CPU Usage per Service + - alert: HighCPUService + expr: rate(process_cpu_seconds_total{job=~"user-service|payment-service|billing-service|notification-service|document-service|utility-service|analytics-service|webhook-service"}[5m]) * 100 > 80 + for: 5m + labels: + severity: warning + category: performance + annotations: + summary: "High CPU usage on {{ $labels.job }}" + description: "CPU usage is {{ $value }}% on {{ $labels.job }}" + + # Slow Database Queries + - alert: SlowDatabaseQueries + expr: histogram_quantile(0.95, rate(db_query_duration_seconds_bucket[5m])) > 0.5 + for: 5m + labels: + severity: warning + category: database + annotations: + summary: "Slow database queries detected" + description: "95th percentile database query time is {{ $value }}s for {{ $labels.table }} table" + + # Database Connection Pool High + - alert: DatabaseConnectionPoolHigh + expr: db_connection_pool_size{state="active"} / (db_connection_pool_size{state="active"} + db_connection_pool_size{state="idle"}) > 0.8 + for: 5m + labels: + severity: warning + category: database + annotations: + summary: "Database connection pool utilization high" + description: "Connection pool utilization is {{ $value | humanizePercentage }} for {{ $labels.database }}" + + # Low Active Users Alert + - alert: LowActiveUsers + expr: active_users < 10 + for: 15m + labels: + severity: info + category: business + annotations: + summary: "Low active users on {{ $labels.service }}" + description: "Only {{ $value }} active users on {{ $labels.service }}" + + # High Payment Failure Rate + - alert: PaymentFailureRateHigh + expr: rate(payment_transactions_total{status="failed"}[5m]) / clamp_min(rate(payment_transactions_total[5m]), 1) > 0.05 + for: 5m + labels: + severity: critical + category: business + service: payment-service + annotations: + summary: "Payment failure rate is high" + description: "Payment failure rate is {{ $value | humanizePercentage }}" + + # Slow Payment Processing + - alert: PaymentProcessingSlow + expr: histogram_quantile(0.95, rate(payment_processing_duration_seconds_bucket[5m])) > 10 + for: 5m + labels: + severity: warning + category: performance + service: payment-service + annotations: + summary: "Payment processing is slow" + description: "95th percentile payment processing time is {{ $value }}s" + + # High Event Bus Message Failures + - alert: EventBusMessageFailures + expr: rate(event_bus_messages_total{status="failed"}[5m]) > 0.1 + for: 5m + labels: + severity: warning + category: messaging + annotations: + summary: "Event bus message failures detected" + description: "Message failure rate is {{ $value }} msg/s for {{ $labels.event_type }}" + + # Saga Execution Failures + - alert: SagaExecutionFailures + expr: rate(saga_executions_total{status="failed"}[5m]) > 0.05 + for: 5m + labels: + severity: critical + category: saga + annotations: + summary: "Saga execution failures detected" + description: "Saga failure rate is {{ $value }} ops/s for {{ $labels.saga_name }}" diff --git a/backend/observability/dashboards/service-overview.json b/backend/observability/dashboards/service-overview.json index e69de29b..4ed5aae2 100644 --- a/backend/observability/dashboards/service-overview.json +++ b/backend/observability/dashboards/service-overview.json @@ -0,0 +1,370 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "links": [], + "panels": [ + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 24, "x": 0, "y": 0}, + "id": 1, + "title": "Service Health Overview", + "type": "stat", + "targets": [ + { + "expr": "up{job=~\"user-service|payment-service|billing-service|notification-service|document-service|utility-service|analytics-service|webhook-service\"}", + "legendFormat": "{{job}}", + "refId": "A" + } + ], + "options": { + "reduceOptions": {"calcs": ["lastNotNull"]}, + "orientation": "auto", + "textMode": "auto", + "colorMode": "background", + "graphMode": "area" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + {"type": "value", "options": {"0": {"text": "DOWN", "color": "red"}, "1": {"text": "UP", "color": "green"}}} + ] + } + } + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 12, "x": 0, "y": 8}, + "id": 2, + "title": "Response Time (p95)", + "type": "graph", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))", + "legendFormat": "{{service}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "s", "label": "Response Time"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 12, "x": 12, "y": 8}, + "id": 3, + "title": "Response Time (p99)", + "type": "graph", + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))", + "legendFormat": "{{service}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "s", "label": "Response Time"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 12, "x": 0, "y": 16}, + "id": 4, + "title": "Request Rate", + "type": "graph", + "targets": [ + { + "expr": "sum(rate(http_requests_total[5m])) by (service)", + "legendFormat": "{{service}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "reqps", "label": "Requests/sec"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 12, "x": 12, "y": 16}, + "id": 5, + "title": "Error Rate (%)", + "type": "graph", + "targets": [ + { + "expr": "sum(rate(http_requests_total{status=~\"5..\"}[5m])) by (service) / sum(rate(http_requests_total[5m])) by (service) * 100", + "legendFormat": "{{service}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "percent", "label": "Error Rate"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 8, "x": 0, "y": 24}, + "id": 6, + "title": "Memory Usage (RSS)", + "type": "graph", + "targets": [ + { + "expr": "process_resident_memory_bytes{job=~\"user-service|payment-service|billing-service|notification-service|document-service|utility-service|analytics-service|webhook-service\"}", + "legendFormat": "{{job}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "bytes", "label": "Memory"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 8, "x": 8, "y": 24}, + "id": 7, + "title": "CPU Usage (%)", + "type": "graph", + "targets": [ + { + "expr": "rate(process_cpu_seconds_total{job=~\"user-service|payment-service|billing-service|notification-service|document-service|utility-service|analytics-service|webhook-service\"}[5m]) * 100", + "legendFormat": "{{job}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "percent", "label": "CPU Usage"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 8, "x": 16, "y": 24}, + "id": 8, + "title": "Active Users", + "type": "graph", + "targets": [ + { + "expr": "active_users", + "legendFormat": "{{service}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "short", "label": "Users"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 12, "x": 0, "y": 32}, + "id": 9, + "title": "Database Query Duration (p95)", + "type": "graph", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(db_query_duration_seconds_bucket[5m])) by (le, service, table))", + "legendFormat": "{{service}} - {{table}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "s", "label": "Duration"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 12, "x": 12, "y": 32}, + "id": 10, + "title": "Database Connection Pool", + "type": "graph", + "targets": [ + { + "expr": "db_connection_pool_size{state=\"active\"}", + "legendFormat": "{{service}} - Active", + "refId": "A" + }, + { + "expr": "db_connection_pool_size{state=\"idle\"}", + "legendFormat": "{{service}} - Idle", + "refId": "B" + } + ], + "yAxes": [ + {"format": "short", "label": "Connections"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 12, "x": 0, "y": 40}, + "id": 11, + "title": "Payment Transactions", + "type": "graph", + "targets": [ + { + "expr": "rate(payment_transactions_total[5m])", + "legendFormat": "{{service}} - {{status}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "ops", "label": "Transactions/sec"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 12, "x": 12, "y": 40}, + "id": 12, + "title": "Payment Processing Duration (p95)", + "type": "graph", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(payment_processing_duration_seconds_bucket[5m])) by (le, method))", + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "s", "label": "Duration"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 8, "x": 0, "y": 48}, + "id": 13, + "title": "Bills Created (Total)", + "type": "stat", + "targets": [ + { + "expr": "sum(bills_created_total) by (service)", + "legendFormat": "{{service}}", + "refId": "A" + } + ], + "options": { + "reduceOptions": {"calcs": ["lastNotNull"]}, + "orientation": "auto", + "textMode": "auto", + "colorMode": "value" + } + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 8, "x": 8, "y": 48}, + "id": 14, + "title": "Event Bus Messages (Rate)", + "type": "graph", + "targets": [ + { + "expr": "sum(rate(event_bus_messages_total[5m])) by (event_type, service)", + "legendFormat": "{{service}} - {{event_type}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "msg/s", "label": "Messages/sec"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 8, "x": 16, "y": 48}, + "id": 15, + "title": "Saga Executions", + "type": "graph", + "targets": [ + { + "expr": "sum(rate(saga_executions_total[5m])) by (saga_name, status)", + "legendFormat": "{{saga_name}} - {{status}}", + "refId": "A" + } + ], + "yAxes": [ + {"format": "ops", "label": "Executions/sec"}, + {"format": "short", "show": false} + ] + }, + { + "datasource": "Prometheus", + "gridPos": {"h": 8, "w": 24, "x": 0, "y": 56}, + "id": 16, + "title": "SLA Compliance", + "type": "table", + "targets": [ + { + "expr": "avg_over_time(up[1h]) * 100", + "legendFormat": "{{job}} Availability (%)", + "refId": "A" + } + ], + "columns": [ + {"text": "Service", "value": "job"}, + {"text": "Availability (%)", "value": "Value"} + ], + "styles": [ + { + "pattern": "Value", + "type": "number", + "unit": "percent", + "thresholds": [ + {"color": "red", "value": 0}, + {"color": "yellow", "value": 99}, + {"color": "green", "value": 99.9} + ] + } + ] + } + ], + "refresh": "30s", + "schemaVersion": 27, + "style": "dark", + "tags": ["performance", "monitoring", "services"], + "templating": { + "list": [ + { + "current": "", + "name": "service", + "options": [ + {"text": "All", "value": ""}, + {"text": "User Service", "value": "user-service"}, + {"text": "Payment Service", "value": "payment-service"}, + {"text": "Billing Service", "value": "billing-service"}, + {"text": "Notification Service", "value": "notification-service"}, + {"text": "Document Service", "value": "document-service"}, + {"text": "Utility Service", "value": "utility-service"}, + {"text": "Analytics Service", "value": "analytics-service"}, + {"text": "Webhook Service", "value": "webhook-service"} + ], + "query": "user-service|payment-service|billing-service|notification-service|document-service|utility-service|analytics-service|webhook-service", + "type": "custom" + } + ] + }, + "time": {"from": "now-1h", "to": "now"}, + "timepicker": {}, + "timezone": "", + "title": "Service Performance Overview", + "uid": "service-overview", + "version": 1 +} diff --git a/backend/observability/monitoring/DatabaseMonitor.ts b/backend/observability/monitoring/DatabaseMonitor.ts new file mode 100644 index 00000000..f7a0870c --- /dev/null +++ b/backend/observability/monitoring/DatabaseMonitor.ts @@ -0,0 +1,204 @@ +// Database performance monitoring integration +import metricsCollector from '../metrics/MetricsCollector'; +import { createLogger } from '../logger/StructuredLogger'; +import TracingMiddleware from '../tracing/TracingMiddleware'; + +const logger = createLogger('database-monitor'); + +export interface QueryMetrics { + operation: string; + table: string; + duration: number; + success: boolean; + recordCount?: number; +} + +export class DatabaseMonitor { + private static instance: DatabaseMonitor; + private queryLog: QueryMetrics[] = []; + private readonly maxLogSize = 1000; + + private constructor() {} + + static getInstance(): DatabaseMonitor { + if (!DatabaseMonitor.instance) { + DatabaseMonitor.instance = new DatabaseMonitor(); + } + return DatabaseMonitor.instance; + } + + /** + * Execute a database query with performance tracking + */ + async executeQuery( + operation: string, + table: string, + queryFn: () => Promise, + service: string + ): Promise { + const start = Date.now(); + let success = true; + let result: T; + + try { + // Execute with tracing if available + result = await TracingMiddleware.traceDatabase( + operation, + `${operation} on ${table}`, + queryFn + ); + return result; + } catch (error) { + success = false; + throw error; + } finally { + const duration = (Date.now() - start) / 1000; // Convert to seconds + + // Record metrics + metricsCollector.recordDbQuery(operation, table, duration, service); + + // Log query metrics + this.logQuery({ + operation, + table, + duration, + success, + }); + + // Log slow queries + if (duration > 1) { + logger.warn('Slow database query detected', { + operation, + table, + duration, + service, + threshold: 1000, + }); + } + } + } + + /** + * Wrap Prisma client with performance monitoring + */ + wrapPrismaClient(client: T, service: string): T { + const wrapper = new Proxy(client, { + get: (target: any, prop: string | symbol) => { + const original = target[prop]; + + if (typeof original === 'function') { + return (...args: any[]) => { + return this.executeQuery( + `prisma.${String(prop)}`, + String(prop), + () => original.apply(target, args), + service + ); + }; + } + + if (typeof original === 'object' && original !== null) { + return this.wrapPrismaClient(original, service); + } + + return original; + }, + }); + + return wrapper; + } + + /** + * Monitor connection pool + */ + updateConnectionPool( + service: string, + database: string, + active: number, + idle: number + ) { + metricsCollector.setDbConnectionPool('active', active, database, service); + metricsCollector.setDbConnectionPool('idle', idle, database, service); + } + + /** + * Log query for analysis + */ + private logQuery(metrics: QueryMetrics) { + this.queryLog.push(metrics); + + // Trim log if too large + if (this.queryLog.length > this.maxLogSize) { + this.queryLog = this.queryLog.slice(-this.maxLogSize); + } + + logger.performance(`db.${metrics.operation}`, metrics.duration * 1000, { + table: metrics.table, + success: metrics.success, + type: 'database_query', + }); + } + + /** + * Get query statistics + */ + getQueryStats(): { + totalQueries: number; + averageDuration: number; + slowQueries: number; + errors: number; + topSlowTables: Array<{ table: string; avgDuration: number; count: number }>; + } { + const queries = this.queryLog; + const total = queries.length; + + if (total === 0) { + return { + totalQueries: 0, + averageDuration: 0, + slowQueries: 0, + errors: 0, + topSlowTables: [], + }; + } + + const avgDuration = queries.reduce((sum, q) => sum + q.duration, 0) / total; + const slowQueries = queries.filter(q => q.duration > 1).length; + const errors = queries.filter(q => !q.success).length; + + // Calculate per-table statistics + const tableStats = new Map(); + queries.forEach(q => { + const current = tableStats.get(q.table) || { totalDuration: 0, count: 0 }; + current.totalDuration += q.duration; + current.count++; + tableStats.set(q.table, current); + }); + + const topSlowTables = Array.from(tableStats.entries()) + .map(([table, stats]) => ({ + table, + avgDuration: stats.totalDuration / stats.count, + count: stats.count, + })) + .sort((a, b) => b.avgDuration - a.avgDuration) + .slice(0, 10); + + return { + totalQueries: total, + averageDuration: avgDuration, + slowQueries, + errors, + topSlowTables, + }; + } + + /** + * Clear query log + */ + clearLog() { + this.queryLog = []; + } +} + +export default DatabaseMonitor.getInstance(); From 412fb13605ce5142eaa7ac99dcf802a60a0e942c Mon Sep 17 00:00:00 2001 From: Ebuka321 Date: Tue, 28 Apr 2026 03:44:17 -0700 Subject: [PATCH 2/4] Fix merge conflicts in package.json --- backend/package.json | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/backend/package.json b/backend/package.json index ebd3c6d6..598f5f84 100644 --- a/backend/package.json +++ b/backend/package.json @@ -57,10 +57,7 @@ "@opentelemetry/instrumentation-express": "^0.34.0", "@prisma/instrumentation": "^5.6.0", "prom-client": "^15.0.0", -<<<<<<< HEAD:backend/package.json -======= "isomorphic-dompurify": "^2.0.0", ->>>>>>> fix/caching-error-handling-performance:package.json "ws": "^8.14.2", "ethers": "^6.8.0", "web3": "^4.2.0", @@ -70,17 +67,13 @@ "useragent": "^2.3.0", "@aws-sdk/client-s3": "^3.400.0", "@aws-sdk/client-cloudwatch": "^3.400.0", - "@aws-sdk/client-ses": "^3.400.0", -<<<<<<< HEAD:backend/package.json + "@aws-sdk/client-es": "^3.400.0", "rss": "^1.2.2", "csv-writer": "^1.6.0", "xlsx": "^0.18.5", "jspdf": "^2.5.1", "html2canvas": "^1.4.1", "exceljs": "^4.4.0" -======= - "rss": "^1.2.2" ->>>>>>> fix/caching-error-handling-performance:package.json }, "devDependencies": { "@types/express": "^4.17.21", @@ -106,6 +99,7 @@ "@types/geoip-lite": "^1.4.2", "@types/node-cron": "^3.0.8", "@types/useragent": "^2.3.1", + "@types/isomorphic-dompurify": "^2.0.0", "jest-environment-jsdom": "^29.7.0", "typescript": "^5.2.2", "prisma": "^5.6.0", @@ -122,21 +116,15 @@ "@typescript-eslint/parser": "^6.14.0", "@types/jest-environment-jsdom": "^29.5.1", "@types/performance-now": "^2.0.2", -<<<<<<< HEAD:backend/package.json "@types/web3": "^1.2.2", "@types/rss": "^0.0.32", - "@types/xlsx": "^0.0.36" -======= - "@types/isomorphic-dompurify": "^2.0.0", + "@types/xlsx": "^0.0.36", "cypress": "^13.6.0", "cypress-visual-regression": "^5.0.0", "cypress-mochawesome-reporter": "^3.6.0", "cypress-xpath": "^2.0.1", "playwright": "^1.40.0", - "@playwright/test": "^1.40.0", - "@types/web3": "^1.2.2", - "@types/rss": "^0.0.32" ->>>>>>> fix/caching-error-handling-performance:package.json + "@playwright/test": "^1.40.0" }, "scripts": { "dev": "ts-node server.ts", @@ -198,10 +186,4 @@ "audit:generate": "npx prisma generate --schema=./databases/audit-service/schema.prisma", "audit:migrate": "npx prisma db push --schema=./databases/audit-service/schema.prisma", "audit:cleanup": "ts-node -e \"import('./services/AuditCleanupService').then(m => m.auditCleanupService.performCleanup())\"", - "audit:archive": "ts-node -e \"import('./services/AuditCleanupService').then(m => m.auditCleanupService.performArchival())\"", - "audit:health": "ts-node -e \"import('./databases/clients/auditClient').then(m => m.default.healthCheck().then(h => console.log('Audit DB Health:', h)))\"", - "audit:stats": "ts-node -e \"import('./services/AuditService').then(m => m.auditService.searchAuditLogs({limit: 1}).then(r => console.log('Total Audit Logs:', r.total)))\"", - "test:audit": "ts-node scripts/test-audit-system.ts", - "check:audit": "ts-node scripts/check-audit-setup.ts" - } -} + "aud From a0c7e28c8f9fa269667f758290dc6029fd3b29d9 Mon Sep 17 00:00:00 2001 From: Ebuka321 Date: Tue, 28 Apr 2026 03:45:35 -0700 Subject: [PATCH 3/4] Add root package.json for CI compatibility --- package.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 00000000..7897d974 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "nepa-monorepo", + "version": "1.0.0", + "description": "NEPA Monorepo - Backend services", + "private": true, + "workspaces": [ + "backend" + ], + "scripts": { + "test": "cd backend && npm test", + "lint": "cd backend && npm run lint", + "build": "cd backend && npm run build", + "dev": "cd backend && npm run dev" + } +} From 1d0a05426b89e3f664bdecede8b00fe5efb79e3d Mon Sep 17 00:00:00 2001 From: Ebuka321 Date: Tue, 28 Apr 2026 03:50:46 -0700 Subject: [PATCH 4/4] Fix JSON syntax errors in backend/package.json --- backend/package.json | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/backend/package.json b/backend/package.json index 598f5f84..aaa15ac4 100644 --- a/backend/package.json +++ b/backend/package.json @@ -67,13 +67,14 @@ "useragent": "^2.3.0", "@aws-sdk/client-s3": "^3.400.0", "@aws-sdk/client-cloudwatch": "^3.400.0", - "@aws-sdk/client-es": "^3.400.0", + "@aws-sdk/client-ses": "^3.400.0", "rss": "^1.2.2", "csv-writer": "^1.6.0", "xlsx": "^0.18.5", "jspdf": "^2.5.1", "html2canvas": "^1.4.1", - "exceljs": "^4.4.0" + "exceljs": "^4.4.0", + "rss": "^1.2.2" }, "devDependencies": { "@types/express": "^4.17.21", @@ -99,7 +100,6 @@ "@types/geoip-lite": "^1.4.2", "@types/node-cron": "^3.0.8", "@types/useragent": "^2.3.1", - "@types/isomorphic-dompurify": "^2.0.0", "jest-environment-jsdom": "^29.7.0", "typescript": "^5.2.2", "prisma": "^5.6.0", @@ -119,12 +119,15 @@ "@types/web3": "^1.2.2", "@types/rss": "^0.0.32", "@types/xlsx": "^0.0.36", + "@types/isomorphic-dompurify": "^2.0.0", "cypress": "^13.6.0", "cypress-visual-regression": "^5.0.0", "cypress-mochawesome-reporter": "^3.6.0", "cypress-xpath": "^2.0.1", "playwright": "^1.40.0", - "@playwright/test": "^1.40.0" + "@playwright/test": "^1.40.0", + "@types/web3": "^1.2.2", + "@types/rss": "^0.0.32" }, "scripts": { "dev": "ts-node server.ts", @@ -186,4 +189,10 @@ "audit:generate": "npx prisma generate --schema=./databases/audit-service/schema.prisma", "audit:migrate": "npx prisma db push --schema=./databases/audit-service/schema.prisma", "audit:cleanup": "ts-node -e \"import('./services/AuditCleanupService').then(m => m.auditCleanupService.performCleanup())\"", - "aud + "audit:archive": "ts-node -e \"import('./services/AuditCleanupService').then(m => m.auditCleanupService.performArchival())\"", + "audit:health": "ts-node -e \"import('./databases/clients/auditClient').then(m => m.default.healthCheck().then(h => console.log('Audit DB Health:', h)))\"", + "audit:stats": "ts-node -e \"import('./services/AuditService').then(m => m.auditService.searchAuditLogs({limit: 1}).then(r => console.log('Total Audit Logs:', r.total)))\"", + "test:audit": "ts-node scripts/test-audit-system.ts", + "check:audit": "ts-node scripts/check-audit-setup.ts" + } +}