feat(gateway): include production Telegram user gateway

Version the NestJS TDLib gateway with Docker deployment, migrations, automated tests and platform integration documentation while excluding all account sessions, credentials, runtime databases and backups.
This commit is contained in:
wmq
2026-08-01 18:38:20 +08:00
parent af49d22ca7
commit 06112602ec
142 changed files with 23107 additions and 7 deletions
+165
View File
@@ -0,0 +1,165 @@
// Preload .env before any module imports
import * as dotenv from 'dotenv';
dotenv.config({ path: ['.env', '.env.local'] });
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
import { appConfig } from './config/app.config';
import { databaseConfig } from './config/database.config';
import { redisConfig } from './config/redis.config';
import { rateLimitConfig } from './config/rate-limit.config';
import { JwtAuthGuard } from './common/guards/jwt-auth.guard';
import { TenantsModule } from './modules/tenants/tenants.module';
import { AuthModule } from './modules/auth/auth.module';
import { TgAccountsModule } from './modules/tg-accounts/tg-accounts.module';
import { TgAuthModule } from './modules/tg-auth/tg-auth.module';
import { TgProxiesModule } from './modules/tg-proxies/tg-proxies.module';
import { TdlibModule } from './modules/tdlib/tdlib.module';
import { TgChatsModule } from './modules/tg-chats/tg-chats.module';
import { TgDialogsModule } from './modules/tg-dialogs/tg-dialogs.module';
import { TgContactsModule } from './modules/tg-contacts/tg-contacts.module';
import { TgMessagesModule } from './modules/tg-messages/tg-messages.module';
import { TgGroupsModule } from './modules/tg-groups/tg-groups.module';
import { TgChannelsModule } from './modules/tg-channels/tg-channels.module';
import { TgFilesModule } from './modules/tg-files/tg-files.module';
import { TgWebhooksModule } from './modules/tg-webhooks/tg-webhooks.module';
import { TgRateLimitModule } from './modules/tg-rate-limit/tg-rate-limit.module';
import { TgAuditModule } from './modules/tg-audit/tg-audit.module';
import { AdminModule } from './modules/admin/admin.module';
import { TgUpdatesModule } from './modules/tg-updates/tg-updates.module';
import { AuditLogInterceptor } from './common/interceptors/audit-log.interceptor';
// Conditionally import BullMQ
const redisEnabled = process.env.REDIS_ENABLED !== 'false';
const bullImports: any[] = [];
const bullProviders: any[] = [];
if (redisEnabled) {
const { BullModule } = require('@nestjs/bull');
bullImports.push(
BullModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
redis: {
host: config.get('redis.host'),
port: config.get('redis.port'),
password: config.get('redis.password'),
db: config.get('redis.db'),
},
}),
}),
);
} else {
// Provide mock Bull queue tokens so injectors don't crash
const { getQueueToken } = require('@nestjs/bull');
const queueNames = ['send-message', 'file-download', 'webhook-delivery'];
for (const name of queueNames) {
bullProviders.push({
provide: getQueueToken(name),
useValue: { add: () => Promise.reject(new Error('Redis/BullMQ not available')), process: () => {} },
});
bullProviders.push({
provide: 'BullQueue_' + name,
useValue: { add: () => Promise.reject(new Error('Redis/BullMQ not available')), process: () => {} },
});
}
}
const imports: any[] = [
ConfigModule.forRoot({
isGlobal: true,
load: [appConfig, databaseConfig, redisConfig, rateLimitConfig],
envFilePath: ['.env'],
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => {
const dbType = config.get('database.type') || 'postgres';
if (dbType === 'sqlite') {
const sqlitePath = config.get('database.sqlitePath') || 'data/gateway.sqlite';
const inMemory = sqlitePath === ':memory:';
return {
type: 'sqljs',
...(inMemory ? {} : { location: sqlitePath }),
autoSave: !inMemory,
entities: [__dirname + '/database/entities/**/*.entity.{ts,js}'],
synchronize: true,
};
}
return {
type: 'postgres',
host: config.get('database.host'),
port: config.get('database.port'),
username: config.get('database.username'),
password: config.get('database.password'),
database: config.get('database.database'),
entities: [__dirname + '/database/entities/**/*.entity.{ts,js}'],
synchronize:
config.get('database.synchronize') ||
config.get('app.nodeEnv') === 'development',
migrationsRun: config.get('database.migrationsRun') || false,
migrations: [__dirname + '/database/migrations/*.{ts,js}'],
logging: config.get('app.nodeEnv') === 'development',
};
},
}),
...bullImports,
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
throttlers: [
{
ttl: config.get('rateLimit.defaultTtl') || 60000,
limit: config.get('rateLimit.defaultLimit') || 30,
},
],
}),
}),
TenantsModule,
AuthModule,
TgAccountsModule,
TgAuthModule,
TgProxiesModule,
TdlibModule,
TgChatsModule,
TgDialogsModule,
TgContactsModule,
TgMessagesModule,
TgGroupsModule,
TgChannelsModule,
TgFilesModule,
TgWebhooksModule,
TgRateLimitModule,
TgAuditModule,
AdminModule,
TgUpdatesModule,
];
@Module({
imports,
providers: [
{
provide: APP_GUARD,
useClass: JwtAuthGuard,
},
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
{
provide: APP_INTERCEPTOR,
useClass: AuditLogInterceptor,
},
...bullProviders,
],
})
export class AppModule {}