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,35 @@
import mongoose from 'mongoose';
import { MongoMemoryServer } from 'mongodb-memory-server';
let mongoServer;
export const connectDatabase = async () => {
mongoServer = await MongoMemoryServer.create();
const uri = mongoServer.getUri();
await mongoose.connect(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
};
export const closeDatabase = async () => {
await mongoose.connection.dropDatabase();
await mongoose.connection.close();
if (mongoServer) {
await mongoServer.stop();
}
};
export const clearDatabase = async () => {
const collections = mongoose.connection.collections;
for (const key in collections) {
const collection = collections[key];
await collection.deleteMany();
}
};
export const seedDatabase = async (model, data) => {
return await model.create(data);
};

View File

@@ -0,0 +1,202 @@
import { faker } from '@faker-js/faker';
// User factory
export const createUser = (overrides = {}) => ({
username: faker.internet.userName(),
email: faker.internet.email(),
password: 'Test123!@#',
role: 'user',
isActive: true,
...overrides
});
// Telegram user factory
export const createTelegramUser = (overrides = {}) => ({
telegramId: faker.string.numeric(10),
username: faker.internet.userName(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
phoneNumber: faker.phone.number('+1##########'),
languageCode: faker.helpers.arrayElement(['en', 'es', 'fr', 'de']),
status: 'active',
tags: [],
groups: [],
customFields: {},
engagement: {
lastActivity: faker.date.recent(),
messagesSent: faker.number.int({ min: 0, max: 100 }),
messagesReceived: faker.number.int({ min: 0, max: 100 }),
conversions: faker.number.int({ min: 0, max: 10 })
},
...overrides
});
// Campaign factory
export const createCampaign = (overrides = {}) => ({
name: faker.lorem.words(3),
description: faker.lorem.sentence(),
type: faker.helpers.arrayElement(['message', 'invitation', 'data_collection', 'engagement', 'custom']),
status: 'draft',
content: {
customMessage: faker.lorem.paragraph(),
media: []
},
targeting: {
includedUsers: [],
excludedUsers: [],
segments: [],
groups: [],
tags: [],
filters: {}
},
settings: {
rateLimit: {
messagesPerSecond: 10,
messagesPerUser: 1
}
},
goals: {
targetAudience: faker.number.int({ min: 100, max: 10000 }),
conversionRate: faker.number.float({ min: 1, max: 30, precision: 0.1 }),
revenue: faker.number.int({ min: 1000, max: 100000 })
},
statistics: {
messagesSent: 0,
delivered: 0,
read: 0,
clicked: 0,
conversions: 0,
revenue: 0
},
...overrides
});
// Scheduled campaign factory
export const createScheduledCampaign = (campaignId, overrides = {}) => ({
campaignId,
name: faker.lorem.words(3),
description: faker.lorem.sentence(),
type: faker.helpers.arrayElement(['one-time', 'recurring', 'trigger-based']),
status: 'active',
schedule: {
startDateTime: faker.date.future(),
recurring: {
pattern: 'daily',
frequency: {
interval: 1,
unit: 'day'
},
time: '09:00',
timezone: 'America/New_York'
}
},
...overrides
});
// Message template factory
export const createTemplate = (overrides = {}) => ({
name: faker.lorem.words(2),
category: faker.helpers.arrayElement(['promotional', 'transactional', 'informational', 'onboarding']),
content: {
en: faker.lorem.paragraph(),
es: faker.lorem.paragraph(),
fr: faker.lorem.paragraph()
},
variables: ['firstName', 'lastName'],
isActive: true,
...overrides
});
// Webhook factory
export const createWebhook = (overrides = {}) => ({
name: faker.lorem.words(2),
url: faker.internet.url(),
events: ['campaign.completed', 'campaign.failed'],
headers: {
'X-Webhook-Secret': faker.string.alphanumeric(32)
},
isActive: true,
retryPolicy: {
maxRetries: 3,
retryDelay: 1000
},
...overrides
});
// User segment factory
export const createSegment = (overrides = {}) => ({
name: faker.lorem.words(2),
description: faker.lorem.sentence(),
criteria: [
{
field: 'tags',
operator: 'contains',
value: 'active',
logic: 'AND'
}
],
isDynamic: true,
...overrides
});
// A/B test factory
export const createABTest = (campaignId, overrides = {}) => ({
name: faker.lorem.words(3),
description: faker.lorem.sentence(),
campaignId,
status: 'draft',
variants: [
{
name: 'Control',
weight: 50,
content: {
customMessage: faker.lorem.paragraph()
}
},
{
name: 'Variant A',
weight: 50,
content: {
customMessage: faker.lorem.paragraph()
}
}
],
metrics: ['open_rate', 'click_rate', 'conversion_rate'],
startDate: faker.date.future(),
endDate: faker.date.future(),
...overrides
});
// Workflow factory
export const createWorkflow = (overrides = {}) => ({
name: faker.lorem.words(3),
description: faker.lorem.sentence(),
triggerType: faker.helpers.arrayElement(['event', 'schedule', 'manual']),
status: 'active',
steps: [
{
id: faker.string.uuid(),
type: 'send_message',
config: {
templateId: faker.string.uuid(),
delay: 0
}
}
],
...overrides
});
// Analytics data factory
export const createAnalyticsData = (overrides = {}) => ({
campaignId: faker.string.uuid(),
date: faker.date.recent(),
metrics: {
sent: faker.number.int({ min: 100, max: 1000 }),
delivered: faker.number.int({ min: 90, max: 950 }),
read: faker.number.int({ min: 50, max: 800 }),
clicked: faker.number.int({ min: 10, max: 200 }),
conversions: faker.number.int({ min: 5, max: 50 }),
revenue: faker.number.float({ min: 1000, max: 10000, precision: 0.01 })
},
...overrides
});

View File

@@ -0,0 +1,49 @@
import redis from 'redis-mock';
let redisClient;
export const connectRedis = async () => {
redisClient = redis.createClient();
return redisClient;
};
export const closeRedis = async () => {
if (redisClient) {
await redisClient.quit();
}
};
export const clearRedis = async () => {
if (redisClient) {
await redisClient.flushall();
}
};
export const getRedisClient = () => redisClient;
// Mock Redis methods for testing
export const mockRedisClient = {
get: jest.fn(),
set: jest.fn(),
del: jest.fn(),
exists: jest.fn(),
expire: jest.fn(),
ttl: jest.fn(),
hget: jest.fn(),
hset: jest.fn(),
hdel: jest.fn(),
hgetall: jest.fn(),
sadd: jest.fn(),
srem: jest.fn(),
smembers: jest.fn(),
sismember: jest.fn(),
zadd: jest.fn(),
zrem: jest.fn(),
zrange: jest.fn(),
zrevrange: jest.fn(),
publish: jest.fn(),
subscribe: jest.fn(),
unsubscribe: jest.fn(),
on: jest.fn(),
quit: jest.fn(),
};