Initial commit: Telegram Management System
Some checks failed
Deploy / deploy (push) Has been cancelled
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:
@@ -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;
|
||||
Reference in New Issue
Block a user