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,178 @@
import express from 'express';
import { realtimeAnalytics } from '../services/realtimeAnalytics.js';
import { validateRequest } from '../middleware/validateRequest.js';
import Joi from 'joi';
const router = express.Router();
// Validation schemas
const recordMetricSchema = Joi.object({
accountId: Joi.string().required(),
metricType: Joi.string().required(),
value: Joi.number().default(1),
metadata: Joi.object().optional()
});
const getMetricsSchema = Joi.object({
metrics: Joi.array().items(Joi.string()).required(),
timeRange: Joi.string().valid('minute', 'hour', 'day').default('hour')
});
const funnelSchema = Joi.object({
steps: Joi.array().items(Joi.object({
name: Joi.string().required(),
metric: Joi.string().required()
})).required(),
timeRange: Joi.string().valid('minute', 'hour', 'day').default('day')
});
// Record a metric
router.post('/metric', validateRequest(recordMetricSchema), async (req, res, next) => {
try {
const { accountId, metricType, value, metadata } = req.body;
await realtimeAnalytics.recordMetric(accountId, metricType, value, metadata);
res.json({
success: true,
message: 'Metric recorded'
});
} catch (error) {
next(error);
}
});
// Get real-time metrics
router.get('/:accountId/metrics', validateRequest(getMetricsSchema, 'query'), async (req, res, next) => {
try {
const { accountId } = req.params;
const { metrics, timeRange } = req.query;
const data = await realtimeAnalytics.getRealtimeMetrics(
accountId,
metrics,
timeRange
);
res.json({
accountId,
timeRange,
metrics: data,
timestamp: new Date()
});
} catch (error) {
next(error);
}
});
// Get dashboard data
router.get('/:accountId/dashboard', async (req, res, next) => {
try {
const { accountId } = req.params;
const dashboardData = await realtimeAnalytics.getDashboardData(accountId);
res.json(dashboardData);
} catch (error) {
next(error);
}
});
// Get funnel analytics
router.post('/:accountId/funnel', validateRequest(funnelSchema), async (req, res, next) => {
try {
const { accountId } = req.params;
const { steps, timeRange } = req.body;
const funnelData = await realtimeAnalytics.getFunnelAnalytics(
accountId,
steps,
timeRange
);
res.json({
accountId,
timeRange,
funnel: funnelData,
timestamp: new Date()
});
} catch (error) {
next(error);
}
});
// Get cohort analytics
router.get('/:accountId/cohorts', async (req, res, next) => {
try {
const { accountId } = req.params;
const { cohortType = 'new_users', metric = 'active_users', periods = 7 } = req.query;
const cohortData = await realtimeAnalytics.getCohortAnalytics(
accountId,
cohortType,
metric,
parseInt(periods)
);
res.json({
accountId,
cohortType,
metric,
cohorts: cohortData,
timestamp: new Date()
});
} catch (error) {
next(error);
}
});
// WebSocket endpoint for real-time streaming
router.ws('/:accountId/stream', (ws, req) => {
const { accountId } = req.params;
let unsubscribe;
ws.on('message', (msg) => {
try {
const { action, metrics } = JSON.parse(msg);
if (action === 'subscribe' && metrics) {
// Set up metric streaming
unsubscribe = realtimeAnalytics.streamMetrics(
accountId,
metrics,
(data) => {
ws.send(JSON.stringify({
type: 'metric',
data
}));
}
);
ws.send(JSON.stringify({
type: 'subscribed',
metrics
}));
} else if (action === 'unsubscribe' && unsubscribe) {
unsubscribe();
unsubscribe = null;
ws.send(JSON.stringify({
type: 'unsubscribed'
}));
}
} catch (error) {
ws.send(JSON.stringify({
type: 'error',
message: error.message
}));
}
});
ws.on('close', () => {
if (unsubscribe) {
unsubscribe();
}
});
});
export default router;