Initial commit: Telegram Management System
Some checks failed
Deploy / deploy (push) Has been cancelled

Full-stack web application for Telegram management
- Frontend: Vue 3 + Vben Admin
- Backend: NestJS
- Features: User management, group broadcast, statistics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
你的用户名
2025-11-04 15:37:50 +08:00
commit 237c7802e5
3674 changed files with 525172 additions and 0 deletions

View File

@@ -0,0 +1,319 @@
import promClient from 'prom-client';
import { logger } from './logger.js';
// Create a Registry
const register = new promClient.Registry();
// Add default metrics
promClient.collectDefaultMetrics({ register });
// Define custom metrics
const httpRequestDuration = new promClient.Histogram({
name: 'compliance_guard_http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.1, 0.5, 1, 2, 5]
});
const apiCallCounter = new promClient.Counter({
name: 'compliance_guard_api_calls_total',
help: 'Total number of API calls',
labelNames: ['endpoint', 'status']
});
const consentCounter = new promClient.Counter({
name: 'compliance_guard_consent_total',
help: 'Total number of consent actions',
labelNames: ['type', 'action', 'status']
});
const dataRequestCounter = new promClient.Counter({
name: 'compliance_guard_data_requests_total',
help: 'Total number of data requests',
labelNames: ['type', 'status']
});
const violationCounter = new promClient.Counter({
name: 'compliance_guard_violations_total',
help: 'Total number of compliance violations',
labelNames: ['type', 'severity']
});
const activeDataRequestsGauge = new promClient.Gauge({
name: 'compliance_guard_active_data_requests',
help: 'Number of active data requests',
labelNames: ['type']
});
const pendingConsentRenewalsGauge = new promClient.Gauge({
name: 'compliance_guard_pending_consent_renewals',
help: 'Number of consents pending renewal'
});
const complianceScoreGauge = new promClient.Gauge({
name: 'compliance_guard_compliance_score',
help: 'Overall compliance score',
labelNames: ['regulation']
});
const dataProcessingLatency = new promClient.Histogram({
name: 'compliance_guard_data_processing_latency_seconds',
help: 'Latency of data processing operations',
labelNames: ['operation'],
buckets: [0.01, 0.05, 0.1, 0.5, 1, 5, 10]
});
// Register metrics
register.registerMetric(httpRequestDuration);
register.registerMetric(apiCallCounter);
register.registerMetric(consentCounter);
register.registerMetric(dataRequestCounter);
register.registerMetric(violationCounter);
register.registerMetric(activeDataRequestsGauge);
register.registerMetric(pendingConsentRenewalsGauge);
register.registerMetric(complianceScoreGauge);
register.registerMetric(dataProcessingLatency);
// Metrics recording functions
export const metrics = {
/**
* Record HTTP request duration
*/
recordHttpRequest: (method, route, statusCode, duration) => {
httpRequestDuration
.labels(method, route, statusCode.toString())
.observe(duration);
},
/**
* Record API call
*/
recordApiCall: (endpoint, status) => {
apiCallCounter
.labels(endpoint, status)
.inc();
},
/**
* Record consent action
*/
recordConsentAction: (type, action, status) => {
consentCounter
.labels(type, action, status)
.inc();
},
/**
* Record data request
*/
recordDataRequest: (type, status) => {
dataRequestCounter
.labels(type, status)
.inc();
},
/**
* Record violation
*/
recordViolation: (type, severity) => {
violationCounter
.labels(type, severity)
.inc();
},
/**
* Update active data requests gauge
*/
updateActiveDataRequests: async (getCountsByType) => {
try {
const counts = await getCountsByType();
for (const [type, count] of Object.entries(counts)) {
activeDataRequestsGauge
.labels(type)
.set(count);
}
} catch (error) {
logger.error('Failed to update active data requests metric:', error);
}
},
/**
* Update pending consent renewals
*/
updatePendingConsentRenewals: async (getCount) => {
try {
const count = await getCount();
pendingConsentRenewalsGauge.set(count);
} catch (error) {
logger.error('Failed to update pending consent renewals metric:', error);
}
},
/**
* Update compliance score
*/
updateComplianceScore: (regulation, score) => {
complianceScoreGauge
.labels(regulation)
.set(score);
},
/**
* Record data processing latency
*/
recordDataProcessingLatency: (operation, duration) => {
dataProcessingLatency
.labels(operation)
.observe(duration);
},
/**
* Get metrics for Prometheus
*/
getMetrics: async () => {
return await register.metrics();
},
/**
* Get metrics in JSON format
*/
getMetricsJSON: async () => {
return await register.getMetricsAsJSON();
}
};
// Middleware to record HTTP metrics
export const metricsMiddleware = (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
const route = req.route ? req.route.path : 'unknown';
metrics.recordHttpRequest(
req.method,
route,
res.statusCode,
duration
);
});
next();
};
// Custom metrics for compliance monitoring
class ComplianceMetrics {
constructor() {
this.resetCounters();
}
resetCounters() {
this.counters = {
consentGrants: 0,
consentWithdrawals: 0,
dataRequests: 0,
dataRequestsCompleted: 0,
violations: 0,
violationsResolved: 0
};
}
incrementConsentGrants() {
this.counters.consentGrants++;
}
incrementConsentWithdrawals() {
this.counters.consentWithdrawals++;
}
incrementDataRequests() {
this.counters.dataRequests++;
}
incrementDataRequestsCompleted() {
this.counters.dataRequestsCompleted++;
}
incrementViolations() {
this.counters.violations++;
}
incrementViolationsResolved() {
this.counters.violationsResolved++;
}
getComplianceHealth() {
const health = {
status: 'healthy',
metrics: {
consentCompletionRate: this.counters.consentWithdrawals > 0
? (this.counters.consentGrants / (this.counters.consentGrants + this.counters.consentWithdrawals))
: 1,
dataRequestCompletionRate: this.counters.dataRequests > 0
? (this.counters.dataRequestsCompleted / this.counters.dataRequests)
: 1,
violationResolutionRate: this.counters.violations > 0
? (this.counters.violationsResolved / this.counters.violations)
: 1
}
};
// Determine overall health status
const rates = Object.values(health.metrics);
const avgRate = rates.reduce((a, b) => a + b, 0) / rates.length;
if (avgRate >= 0.95) {
health.status = 'healthy';
} else if (avgRate >= 0.80) {
health.status = 'warning';
} else {
health.status = 'critical';
}
return health;
}
}
export const complianceMetrics = new ComplianceMetrics();
// Periodic metrics update
export const startMetricsCollection = (models) => {
// Update metrics every minute
setInterval(async () => {
try {
// Update active data requests
if (models.DataRequest) {
const counts = await models.DataRequest.aggregate([
{ $match: { status: { $in: ['pending', 'processing'] } } },
{ $group: { _id: '$type', count: { $sum: 1 } } }
]);
const countsByType = counts.reduce((acc, item) => {
acc[item._id] = item.count;
return acc;
}, {});
await metrics.updateActiveDataRequests(async () => countsByType);
}
// Update pending consent renewals
if (models.ConsentRecord) {
await metrics.updatePendingConsentRenewals(async () => {
const thirtyDaysFromNow = new Date();
thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);
return await models.ConsentRecord.countDocuments({
status: 'granted',
renewable: true,
expiryDate: {
$gte: new Date(),
$lte: thirtyDaysFromNow
}
});
});
}
} catch (error) {
logger.error('Failed to update metrics:', error);
}
}, 60000); // Every minute
};