feat: 完成配置中心重构和命名规范优化

- 重构config层为配置中心架构,支持动态配置管理
- 统一core层命名规范(event-bus→event, circuit-breaker→breaker, domain-sdk→sdk)
- 修复数据库连接配置路径问题
- 实现配置中心完整功能:系统配置、动态配置、配置验证、统计
- 优化目录结构,为微服务架构做准备
- 修复TypeScript编译错误和依赖注入问题
This commit is contained in:
万物街
2025-08-28 05:19:14 +08:00
parent 5118d98369
commit 2084711030
137 changed files with 6148 additions and 1856 deletions

View File

@@ -0,0 +1,347 @@
/**
* 应用配置中心
* 集中管理所有配置,避免分散的 process.env 调用
*/
export interface AppConfig {
// 应用基础配置
app: {
name: string;
version: string;
port: number;
environment: string;
timezone: string;
};
// 数据库配置
database: {
host: string;
port: number;
username: string;
password: string;
database: string;
synchronize: boolean;
logging: boolean;
};
// Redis 配置
redis: {
host: string;
port: number;
password: string;
db: number;
keyPrefix: string;
};
// Kafka 配置
kafka: {
clientId: string;
brokers: string[];
groupId: string;
topicPrefix: string;
};
// JWT 配置
jwt: {
secret: string;
expiresIn: string;
algorithm: string;
};
// 缓存配置
cache: {
ttl: number;
maxItems: number;
prefix: string;
};
// 日志配置
logging: {
level: string;
format: string;
filename?: string;
};
// 文件上传配置
upload: {
path: string;
maxSize: number;
allowedTypes: string[];
};
// 限流配置
throttle: {
ttl: number;
limit: number;
};
// 第三方服务配置
thirdParty: {
storage: {
provider: string;
config: Record<string, any>;
};
payment: {
provider: string;
config: Record<string, any>;
};
sms: {
provider: string;
config: Record<string, any>;
};
};
}
/**
* 默认配置
*/
const defaultConfig: AppConfig = {
app: {
name: 'WWJCloud Backend',
version: '1.0.0',
port: 3001,
environment: 'development',
timezone: 'Asia/Shanghai',
},
database: {
host: 'localhost',
port: 3306,
username: 'root',
password: '123456',
database: 'wwjcloud',
synchronize: false,
logging: true,
},
redis: {
host: 'localhost',
port: 6379,
password: '',
db: 0,
keyPrefix: 'wwjcloud:',
},
kafka: {
clientId: 'wwjcloud-backend',
brokers: ['localhost:9092'],
groupId: 'wwjcloud-group',
topicPrefix: 'wwjcloud.',
},
jwt: {
secret: 'your-secret-key',
expiresIn: '24h',
algorithm: 'HS256',
},
cache: {
ttl: 3600,
maxItems: 1000,
prefix: 'cache:',
},
logging: {
level: 'info',
format: 'json',
filename: 'logs/app.log',
},
upload: {
path: 'uploads/',
maxSize: 10 * 1024 * 1024, // 10MB
allowedTypes: ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx'],
},
throttle: {
ttl: 60,
limit: 100,
},
thirdParty: {
storage: {
provider: 'local',
config: {},
},
payment: {
provider: 'mock',
config: {},
},
sms: {
provider: 'mock',
config: {},
},
},
};
/**
* 环境变量配置加载器
*/
function loadFromEnv(): Partial<AppConfig> {
return {
app: {
name: process.env.APP_NAME || defaultConfig.app.name,
version: process.env.APP_VERSION || defaultConfig.app.version,
port: parseInt(process.env.PORT || String(defaultConfig.app.port), 10),
environment: process.env.NODE_ENV || defaultConfig.app.environment,
timezone: process.env.TZ || defaultConfig.app.timezone,
},
database: {
host: process.env.DB_HOST || defaultConfig.database.host,
port: parseInt(process.env.DB_PORT || String(defaultConfig.database.port), 10),
username: process.env.DB_USERNAME || defaultConfig.database.username,
password: process.env.DB_PASSWORD || defaultConfig.database.password,
database: process.env.DB_DATABASE || defaultConfig.database.database,
synchronize: process.env.DB_SYNC === 'true',
logging: process.env.DB_LOGGING === 'true',
},
redis: {
host: process.env.REDIS_HOST || defaultConfig.redis.host,
port: parseInt(process.env.REDIS_PORT || String(defaultConfig.redis.port), 10),
password: process.env.REDIS_PASSWORD || defaultConfig.redis.password,
db: parseInt(process.env.REDIS_DB || String(defaultConfig.redis.db), 10),
keyPrefix: process.env.REDIS_KEY_PREFIX || defaultConfig.redis.keyPrefix,
},
kafka: {
clientId: process.env.KAFKA_CLIENT_ID || defaultConfig.kafka.clientId,
brokers: (process.env.KAFKA_BROKERS || defaultConfig.kafka.brokers.join(',')).split(','),
groupId: process.env.KAFKA_GROUP_ID || defaultConfig.kafka.groupId,
topicPrefix: process.env.KAFKA_TOPIC_PREFIX || defaultConfig.kafka.topicPrefix,
},
jwt: {
secret: process.env.JWT_SECRET || defaultConfig.jwt.secret,
expiresIn: process.env.JWT_EXPIRES_IN || defaultConfig.jwt.expiresIn,
algorithm: process.env.JWT_ALGORITHM || defaultConfig.jwt.algorithm,
},
cache: {
ttl: parseInt(process.env.CACHE_TTL || String(defaultConfig.cache.ttl), 10),
maxItems: parseInt(process.env.CACHE_MAX_ITEMS || String(defaultConfig.cache.maxItems), 10),
prefix: process.env.CACHE_PREFIX || defaultConfig.cache.prefix,
},
logging: {
level: process.env.LOG_LEVEL || defaultConfig.logging.level,
format: process.env.LOG_FORMAT || defaultConfig.logging.format,
filename: process.env.LOG_FILENAME,
},
upload: {
path: process.env.UPLOAD_PATH || defaultConfig.upload.path,
maxSize: parseInt(process.env.UPLOAD_MAX_SIZE || String(defaultConfig.upload.maxSize), 10),
allowedTypes: process.env.UPLOAD_ALLOWED_TYPES?.split(',') || defaultConfig.upload.allowedTypes,
},
throttle: {
ttl: parseInt(process.env.THROTTLE_TTL || String(defaultConfig.throttle.ttl), 10),
limit: parseInt(process.env.THROTTLE_LIMIT || String(defaultConfig.throttle.limit), 10),
},
thirdParty: {
storage: {
provider: process.env.STORAGE_PROVIDER || defaultConfig.thirdParty.storage.provider,
config: JSON.parse(process.env.STORAGE_CONFIG || '{}'),
},
payment: {
provider: process.env.PAYMENT_PROVIDER || defaultConfig.thirdParty.payment.provider,
config: JSON.parse(process.env.PAYMENT_CONFIG || '{}'),
},
sms: {
provider: process.env.SMS_PROVIDER || defaultConfig.thirdParty.sms.provider,
config: JSON.parse(process.env.SMS_CONFIG || '{}'),
},
},
};
}
/**
* 配置合并函数
*/
function mergeConfig(defaultConfig: AppConfig, envConfig: Partial<AppConfig>): AppConfig {
return {
...defaultConfig,
...envConfig,
app: { ...defaultConfig.app, ...envConfig.app },
database: { ...defaultConfig.database, ...envConfig.database },
redis: { ...defaultConfig.redis, ...envConfig.redis },
kafka: { ...defaultConfig.kafka, ...envConfig.kafka },
jwt: { ...defaultConfig.jwt, ...envConfig.jwt },
cache: { ...defaultConfig.cache, ...envConfig.cache },
logging: { ...defaultConfig.logging, ...envConfig.logging },
upload: { ...defaultConfig.upload, ...envConfig.upload },
throttle: { ...defaultConfig.throttle, ...envConfig.throttle },
thirdParty: {
storage: { ...defaultConfig.thirdParty.storage, ...envConfig.thirdParty?.storage },
payment: { ...defaultConfig.thirdParty.payment, ...envConfig.thirdParty?.payment },
sms: { ...defaultConfig.thirdParty.sms, ...envConfig.thirdParty?.sms },
},
};
}
/**
* 应用配置实例
*/
export const appConfig: AppConfig = mergeConfig(defaultConfig, loadFromEnv());
/**
* 配置获取工具函数
*/
export const config = {
// 获取完整配置
get(): AppConfig {
return appConfig;
},
// 获取应用配置
getApp() {
return appConfig.app;
},
// 获取数据库配置
getDatabase() {
return appConfig.database;
},
// 获取 Redis 配置
getRedis() {
return appConfig.redis;
},
// 获取 Kafka 配置
getKafka() {
return appConfig.kafka;
},
// 获取 JWT 配置
getJwt() {
return appConfig.jwt;
},
// 获取缓存配置
getCache() {
return appConfig.cache;
},
// 获取日志配置
getLogging() {
return appConfig.logging;
},
// 获取上传配置
getUpload() {
return appConfig.upload;
},
// 获取限流配置
getThrottle() {
return appConfig.throttle;
},
// 获取第三方服务配置
getThirdParty() {
return appConfig.thirdParty;
},
// 检查是否为生产环境
isProduction(): boolean {
return appConfig.app.environment === 'production';
},
// 检查是否为开发环境
isDevelopment(): boolean {
return appConfig.app.environment === 'development';
},
// 检查是否为测试环境
isTest(): boolean {
return appConfig.app.environment === 'test';
},
};
export default appConfig;

View File

@@ -0,0 +1,35 @@
import { Module } from '@nestjs/common';
import { ConfigModule as NestConfigModule } from '@nestjs/config';
import { ConfigController } from '../controllers/configController';
import { ConfigCenterService } from '../services/configCenterService';
import { ConfigValidationService } from '../services/configValidationService';
import { DynamicConfigService } from '../services/dynamicConfigService';
import { DocsNavigationController } from '../controllers/docsNavigationController';
import { appConfig } from './appConfig';
@Module({
imports: [
NestConfigModule.forRoot({
isGlobal: true,
load: [() => appConfig],
envFilePath: ['.env.local', '.env.development', '.env.production', '.env'],
}),
],
controllers: [ConfigController, DocsNavigationController],
providers: [
ConfigCenterService,
ConfigValidationService,
DynamicConfigService,
{
provide: 'APP_CONFIG',
useValue: appConfig,
},
],
exports: [
ConfigCenterService,
ConfigValidationService,
DynamicConfigService,
'APP_CONFIG',
],
})
export class ConfigModule {}

View File

@@ -0,0 +1,4 @@
// 核心配置导出
export { appConfig, config } from './appConfig';
export type { AppConfig } from './appConfig';
export { ConfigModule } from './configModule';