3.1 整体架构概览
3.1.1 架构设计原则
核心设计原则
// 架构设计原则定义
interface ArchitecturePrinciples {
scalability: ScalabilityPrinciple;
maintainability: MaintainabilityPrinciple;
performance: PerformancePrinciple;
security: SecurityPrinciple;
usability: UsabilityPrinciple;
}
interface ScalabilityPrinciple {
horizontal: string; // 水平扩展能力
vertical: string; // 垂直扩展能力
microservices: string; // 微服务架构
loadBalancing: string; // 负载均衡
}
const architecturePrinciples: ArchitecturePrinciples = {
scalability: {
horizontal: '支持通过增加服务实例来扩展系统容量',
vertical: '支持通过增强单个服务性能来提升处理能力',
microservices: '采用微服务架构,服务间松耦合',
loadBalancing: '实现智能负载均衡和故障转移'
},
maintainability: {
modularity: '模块化设计,职责单一',
codeQuality: '高质量代码,完善的测试覆盖',
documentation: '完整的文档和API规范',
monitoring: '全面的监控和日志系统'
},
performance: {
caching: '多层缓存策略',
optimization: '数据库查询优化',
compression: '数据压缩和传输优化',
cdn: 'CDN加速静态资源'
},
security: {
authentication: '多因素身份认证',
authorization: '细粒度权限控制',
encryption: '数据传输和存储加密',
audit: '完整的审计日志'
},
usability: {
intuitive: '直观的用户界面设计',
responsive: '响应式设计支持多设备',
accessibility: '无障碍访问支持',
performance: '快速的响应时间'
}
};
架构分层设计
graph TB
subgraph "用户层"
A[Web浏览器]
B[移动端App]
C[桌面应用]
end
subgraph "接入层"
D[CDN]
E[负载均衡器]
F[API网关]
end
subgraph "应用层"
G[设计器服务]
H[运行时服务]
I[组件服务]
J[用户服务]
K[工作流服务]
end
subgraph "数据层"
L[MySQL集群]
M[Redis集群]
N[文件存储]
O[搜索引擎]
end
subgraph "基础设施层"
P[容器编排]
Q[服务网格]
R[监控系统]
S[日志系统]
end
A --> D
B --> D
C --> D
D --> E
E --> F
F --> G
F --> H
F --> I
F --> J
F --> K
G --> L
G --> M
H --> L
H --> M
I --> N
J --> L
K --> L
G --> P
H --> P
I --> P
J --> P
K --> P
P --> Q
Q --> R
Q --> S
3.1.2 系统架构图
高层架构视图
// 系统架构定义
interface SystemArchitecture {
layers: ArchitectureLayer[];
services: MicroService[];
dataFlow: DataFlowDefinition;
deployment: DeploymentStrategy;
}
interface ArchitectureLayer {
name: string;
components: string[];
responsibilities: string[];
technologies: string[];
}
const systemArchitecture: SystemArchitecture = {
layers: [
{
name: '表现层 (Presentation Layer)',
components: [
'设计器界面',
'预览界面',
'管理后台',
'移动端应用'
],
responsibilities: [
'用户交互界面',
'数据展示',
'用户输入处理',
'前端路由管理'
],
technologies: ['Vue 3', 'TypeScript', 'Element Plus', 'Vite']
},
{
name: '网关层 (Gateway Layer)',
components: [
'API网关',
'负载均衡器',
'反向代理',
'SSL终端'
],
responsibilities: [
'请求路由',
'身份认证',
'限流控制',
'API聚合'
],
technologies: ['Nginx', 'Kong', 'Envoy', 'Istio']
},
{
name: '业务层 (Business Layer)',
components: [
'设计器服务',
'运行时服务',
'组件服务',
'用户服务',
'工作流服务'
],
responsibilities: [
'业务逻辑处理',
'数据验证',
'业务规则执行',
'服务编排'
],
technologies: ['Node.js', 'Express', 'TypeScript', 'TypeORM']
},
{
name: '数据层 (Data Layer)',
components: [
'MySQL数据库',
'Redis缓存',
'文件存储',
'搜索引擎'
],
responsibilities: [
'数据持久化',
'数据缓存',
'文件管理',
'全文搜索'
],
technologies: ['MySQL', 'Redis', 'MinIO', 'Elasticsearch']
},
{
name: '基础设施层 (Infrastructure Layer)',
components: [
'容器编排',
'服务发现',
'配置管理',
'监控告警'
],
responsibilities: [
'服务部署',
'服务治理',
'配置管理',
'系统监控'
],
technologies: ['Kubernetes', 'Docker', 'Consul', 'Prometheus']
}
],
services: [
{
name: 'api-gateway',
port: 3000,
responsibilities: ['请求路由', '身份认证', '限流控制'],
dependencies: ['auth-service', 'designer-service']
},
{
name: 'auth-service',
port: 3001,
responsibilities: ['用户认证', '权限管理', 'JWT管理'],
dependencies: []
},
{
name: 'designer-service',
port: 3002,
responsibilities: ['页面设计', '组件管理', '模板管理'],
dependencies: ['component-service']
},
{
name: 'component-service',
port: 3003,
responsibilities: ['组件注册', '组件库管理', '版本控制'],
dependencies: []
},
{
name: 'runtime-service',
port: 3004,
responsibilities: ['应用运行', '数据绑定', '事件处理'],
dependencies: ['data-service']
},
{
name: 'data-service',
port: 3005,
responsibilities: ['数据源管理', 'API代理', '数据转换'],
dependencies: []
},
{
name: 'workflow-service',
port: 3006,
responsibilities: ['工作流引擎', '流程设计', '任务调度'],
dependencies: ['notification-service']
},
{
name: 'notification-service',
port: 3007,
responsibilities: ['消息推送', '邮件发送', '系统通知'],
dependencies: []
}
],
dataFlow: {
synchronous: [
'HTTP API调用',
'数据库查询',
'缓存读写'
],
asynchronous: [
'消息队列',
'事件发布订阅',
'异步任务处理'
]
},
deployment: {
containerization: 'Docker容器化',
orchestration: 'Kubernetes编排',
cicd: 'GitLab CI/CD',
monitoring: 'Prometheus + Grafana'
}
};
3.2 微服务架构设计
3.2.1 服务拆分策略
领域驱动设计 (DDD)
// 领域模型定义
interface DomainModel {
boundedContexts: BoundedContext[];
aggregates: Aggregate[];
domainServices: DomainService[];
}
interface BoundedContext {
name: string;
description: string;
entities: string[];
services: string[];
repositories: string[];
}
const domainModel: DomainModel = {
boundedContexts: [
{
name: '用户管理上下文',
description: '负责用户身份认证、权限管理和用户信息维护',
entities: ['User', 'Role', 'Permission', 'UserSession'],
services: ['AuthService', 'UserService', 'RoleService'],
repositories: ['UserRepository', 'RoleRepository']
},
{
name: '设计器上下文',
description: '负责页面设计、布局管理和设计器功能',
entities: ['Project', 'Page', 'Layout', 'Template'],
services: ['DesignerService', 'TemplateService', 'VersionService'],
repositories: ['ProjectRepository', 'PageRepository']
},
{
name: '组件管理上下文',
description: '负责组件库管理、组件注册和版本控制',
entities: ['Component', 'ComponentVersion', 'ComponentCategory'],
services: ['ComponentService', 'RegistryService', 'MarketService'],
repositories: ['ComponentRepository', 'CategoryRepository']
},
{
name: '运行时上下文',
description: '负责应用运行、数据绑定和事件处理',
entities: ['Application', 'DataBinding', 'EventHandler'],
services: ['RuntimeService', 'RenderService', 'EventService'],
repositories: ['ApplicationRepository', 'EventRepository']
},
{
name: '数据管理上下文',
description: '负责数据源管理、API代理和数据转换',
entities: ['DataSource', 'ApiProxy', 'DataTransform'],
services: ['DataService', 'ProxyService', 'TransformService'],
repositories: ['DataSourceRepository', 'ProxyRepository']
},
{
name: '工作流上下文',
description: '负责工作流引擎、流程设计和任务调度',
entities: ['Workflow', 'Process', 'Task', 'Approval'],
services: ['WorkflowService', 'ProcessService', 'TaskService'],
repositories: ['WorkflowRepository', 'ProcessRepository']
}
],
aggregates: [
{
name: 'UserAggregate',
root: 'User',
entities: ['User', 'UserProfile', 'UserPreference'],
invariants: ['用户名唯一性', '邮箱格式验证']
},
{
name: 'ProjectAggregate',
root: 'Project',
entities: ['Project', 'Page', 'Component'],
invariants: ['项目名称唯一性', '页面路径唯一性']
},
{
name: 'ComponentAggregate',
root: 'Component',
entities: ['Component', 'ComponentVersion', 'ComponentDependency'],
invariants: ['组件版本语义化', '依赖循环检测']
}
],
domainServices: [
{
name: 'AuthenticationService',
description: '处理用户认证逻辑',
methods: ['login', 'logout', 'refreshToken', 'validateToken']
},
{
name: 'ComponentValidationService',
description: '验证组件配置和依赖',
methods: ['validateConfig', 'checkDependencies', 'validateSchema']
},
{
name: 'WorkflowExecutionService',
description: '执行工作流程',
methods: ['startProcess', 'executeTask', 'handleApproval']
}
]
};
服务边界定义
// 服务边界和接口定义
interface ServiceBoundary {
serviceName: string;
publicInterface: PublicAPI[];
privateInterface: PrivateAPI[];
dataOwnership: string[];
dependencies: ServiceDependency[];
}
interface PublicAPI {
endpoint: string;
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
description: string;
requestSchema: any;
responseSchema: any;
}
const serviceBoundaries: ServiceBoundary[] = [
{
serviceName: 'auth-service',
publicInterface: [
{
endpoint: '/api/auth/login',
method: 'POST',
description: '用户登录',
requestSchema: {
username: 'string',
password: 'string'
},
responseSchema: {
token: 'string',
user: 'UserInfo',
expiresIn: 'number'
}
},
{
endpoint: '/api/auth/validate',
method: 'POST',
description: '验证令牌',
requestSchema: {
token: 'string'
},
responseSchema: {
valid: 'boolean',
user: 'UserInfo'
}
}
],
privateInterface: [
{
endpoint: '/internal/users/:id',
method: 'GET',
description: '获取用户信息(内部调用)',
requestSchema: {},
responseSchema: {
user: 'UserInfo'
}
}
],
dataOwnership: [
'users',
'roles',
'permissions',
'user_sessions'
],
dependencies: []
},
{
serviceName: 'designer-service',
publicInterface: [
{
endpoint: '/api/projects',
method: 'GET',
description: '获取项目列表',
requestSchema: {
page: 'number',
limit: 'number',
search: 'string'
},
responseSchema: {
projects: 'Project[]',
total: 'number'
}
},
{
endpoint: '/api/projects/:id/pages',
method: 'POST',
description: '创建页面',
requestSchema: {
name: 'string',
path: 'string',
config: 'PageConfig'
},
responseSchema: {
page: 'Page'
}
}
],
privateInterface: [],
dataOwnership: [
'projects',
'pages',
'templates',
'page_versions'
],
dependencies: [
{
service: 'auth-service',
type: 'synchronous',
purpose: '用户认证和权限验证'
},
{
service: 'component-service',
type: 'synchronous',
purpose: '获取组件信息'
}
]
},
{
serviceName: 'component-service',
publicInterface: [
{
endpoint: '/api/components',
method: 'GET',
description: '获取组件列表',
requestSchema: {
category: 'string',
search: 'string',
page: 'number'
},
responseSchema: {
components: 'Component[]',
total: 'number'
}
},
{
endpoint: '/api/components/:id/install',
method: 'POST',
description: '安装组件',
requestSchema: {
version: 'string'
},
responseSchema: {
success: 'boolean',
component: 'Component'
}
}
],
privateInterface: [
{
endpoint: '/internal/components/:id/validate',
method: 'POST',
description: '验证组件配置',
requestSchema: {
config: 'ComponentConfig'
},
responseSchema: {
valid: 'boolean',
errors: 'string[]'
}
}
],
dataOwnership: [
'components',
'component_versions',
'component_categories',
'component_dependencies'
],
dependencies: []
}
];
3.2.2 服务间通信
同步通信:HTTP/REST
// HTTP客户端封装
class ServiceClient {
private baseURL: string;
private timeout: number;
private retryConfig: RetryConfig;
constructor(config: ServiceClientConfig) {
this.baseURL = config.baseURL;
this.timeout = config.timeout || 5000;
this.retryConfig = config.retry || { attempts: 3, delay: 1000 };
}
async request<T>(options: RequestOptions): Promise<T> {
const config = {
...options,
baseURL: this.baseURL,
timeout: this.timeout,
headers: {
'Content-Type': 'application/json',
...options.headers
}
};
return this.executeWithRetry(config);
}
private async executeWithRetry<T>(config: any): Promise<T> {
let lastError: Error;
for (let attempt = 1; attempt <= this.retryConfig.attempts; attempt++) {
try {
const response = await axios(config);
return response.data;
} catch (error) {
lastError = error as Error;
if (attempt < this.retryConfig.attempts) {
await this.delay(this.retryConfig.delay * attempt);
}
}
}
throw lastError!;
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// 服务客户端工厂
class ServiceClientFactory {
private clients: Map<string, ServiceClient> = new Map();
constructor(private config: ServiceConfig) {}
getClient(serviceName: string): ServiceClient {
if (!this.clients.has(serviceName)) {
const serviceConfig = this.config.services[serviceName];
if (!serviceConfig) {
throw new Error(`Service ${serviceName} not configured`);
}
const client = new ServiceClient({
baseURL: serviceConfig.url,
timeout: serviceConfig.timeout,
retry: serviceConfig.retry
});
this.clients.set(serviceName, client);
}
return this.clients.get(serviceName)!;
}
}
// 使用示例
class DesignerService {
private authClient: ServiceClient;
private componentClient: ServiceClient;
constructor(clientFactory: ServiceClientFactory) {
this.authClient = clientFactory.getClient('auth-service');
this.componentClient = clientFactory.getClient('component-service');
}
async createProject(userId: string, projectData: CreateProjectRequest): Promise<Project> {
// 验证用户权限
const user = await this.authClient.request<User>({
method: 'GET',
url: `/internal/users/${userId}`,
headers: {
'X-Internal-Request': 'true'
}
});
if (!user.permissions.includes('project:create')) {
throw new Error('Insufficient permissions');
}
// 验证组件依赖
if (projectData.components) {
for (const componentId of projectData.components) {
await this.componentClient.request({
method: 'POST',
url: `/internal/components/${componentId}/validate`,
data: { config: projectData.config }
});
}
}
// 创建项目
const project = await this.projectRepository.create({
...projectData,
ownerId: userId,
status: 'draft'
});
return project;
}
}
异步通信:消息队列
// 消息队列抽象
interface MessageQueue {
publish(topic: string, message: any): Promise<void>;
subscribe(topic: string, handler: MessageHandler): Promise<void>;
unsubscribe(topic: string): Promise<void>;
}
interface MessageHandler {
(message: any): Promise<void>;
}
// Redis消息队列实现
class RedisMessageQueue implements MessageQueue {
private publisher: Redis;
private subscriber: Redis;
private handlers: Map<string, MessageHandler[]> = new Map();
constructor(redisConfig: RedisConfig) {
this.publisher = new Redis(redisConfig);
this.subscriber = new Redis(redisConfig);
this.setupSubscriber();
}
async publish(topic: string, message: any): Promise<void> {
const serialized = JSON.stringify({
id: uuidv4(),
timestamp: Date.now(),
topic,
data: message
});
await this.publisher.publish(topic, serialized);
}
async subscribe(topic: string, handler: MessageHandler): Promise<void> {
if (!this.handlers.has(topic)) {
this.handlers.set(topic, []);
await this.subscriber.subscribe(topic);
}
this.handlers.get(topic)!.push(handler);
}
async unsubscribe(topic: string): Promise<void> {
this.handlers.delete(topic);
await this.subscriber.unsubscribe(topic);
}
private setupSubscriber(): void {
this.subscriber.on('message', async (topic: string, message: string) => {
const handlers = this.handlers.get(topic);
if (!handlers) return;
try {
const parsedMessage = JSON.parse(message);
// 并行处理所有处理器
await Promise.all(
handlers.map(handler =>
this.executeHandler(handler, parsedMessage.data)
)
);
} catch (error) {
console.error(`Error processing message for topic ${topic}:`, error);
}
});
}
private async executeHandler(handler: MessageHandler, message: any): Promise<void> {
try {
await handler(message);
} catch (error) {
console.error('Message handler error:', error);
// 可以实现重试逻辑或死信队列
}
}
}
// 事件定义
interface DomainEvent {
eventId: string;
eventType: string;
aggregateId: string;
aggregateType: string;
eventData: any;
timestamp: Date;
version: number;
}
// 事件发布器
class EventPublisher {
constructor(private messageQueue: MessageQueue) {}
async publishEvent(event: DomainEvent): Promise<void> {
await this.messageQueue.publish(event.eventType, event);
}
// 项目创建事件
async publishProjectCreated(project: Project): Promise<void> {
const event: DomainEvent = {
eventId: uuidv4(),
eventType: 'project.created',
aggregateId: project.id.toString(),
aggregateType: 'Project',
eventData: {
projectId: project.id,
projectName: project.name,
ownerId: project.ownerId,
createdAt: project.createdAt
},
timestamp: new Date(),
version: 1
};
await this.publishEvent(event);
}
// 组件安装事件
async publishComponentInstalled(componentId: string, projectId: string): Promise<void> {
const event: DomainEvent = {
eventId: uuidv4(),
eventType: 'component.installed',
aggregateId: componentId,
aggregateType: 'Component',
eventData: {
componentId,
projectId,
installedAt: new Date()
},
timestamp: new Date(),
version: 1
};
await this.publishEvent(event);
}
}
// 事件处理器
class ProjectEventHandler {
constructor(
private messageQueue: MessageQueue,
private notificationService: NotificationService
) {
this.setupEventHandlers();
}
private async setupEventHandlers(): Promise<void> {
// 处理项目创建事件
await this.messageQueue.subscribe('project.created', async (event: DomainEvent) => {
const { projectName, ownerId } = event.eventData;
// 发送通知
await this.notificationService.sendNotification({
userId: ownerId,
type: 'project_created',
title: '项目创建成功',
message: `项目 "${projectName}" 已成功创建`,
data: { projectId: event.aggregateId }
});
// 创建默认页面
await this.createDefaultPages(event.aggregateId);
});
// 处理组件安装事件
await this.messageQueue.subscribe('component.installed', async (event: DomainEvent) => {
const { componentId, projectId } = event.eventData;
// 更新项目依赖
await this.updateProjectDependencies(projectId, componentId);
// 记录使用统计
await this.recordComponentUsage(componentId);
});
}
private async createDefaultPages(projectId: string): Promise<void> {
// 创建默认页面的逻辑
console.log(`Creating default pages for project ${projectId}`);
}
private async updateProjectDependencies(projectId: string, componentId: string): Promise<void> {
// 更新项目依赖的逻辑
console.log(`Updating dependencies for project ${projectId}, component ${componentId}`);
}
private async recordComponentUsage(componentId: string): Promise<void> {
// 记录组件使用统计的逻辑
console.log(`Recording usage for component ${componentId}`);
}
}
3.2.3 服务发现与注册
Consul服务发现
// 服务注册接口
interface ServiceRegistry {
register(service: ServiceInfo): Promise<void>;
deregister(serviceId: string): Promise<void>;
discover(serviceName: string): Promise<ServiceInfo[]>;
health(serviceId: string): Promise<HealthStatus>;
}
interface ServiceInfo {
id: string;
name: string;
address: string;
port: number;
tags: string[];
meta: Record<string, string>;
health: HealthCheck;
}
interface HealthCheck {
http?: string;
tcp?: string;
interval: string;
timeout: string;
deregisterCriticalServiceAfter: string;
}
// Consul服务注册实现
class ConsulServiceRegistry implements ServiceRegistry {
private consul: any;
constructor(consulConfig: ConsulConfig) {
this.consul = require('consul')({
host: consulConfig.host,
port: consulConfig.port,
secure: consulConfig.secure
});
}
async register(service: ServiceInfo): Promise<void> {
const registration = {
id: service.id,
name: service.name,
address: service.address,
port: service.port,
tags: service.tags,
meta: service.meta,
check: {
http: service.health.http,
tcp: service.health.tcp,
interval: service.health.interval,
timeout: service.health.timeout,
deregistercriticalserviceafter: service.health.deregisterCriticalServiceAfter
}
};
await this.consul.agent.service.register(registration);
console.log(`Service ${service.name} registered with ID ${service.id}`);
}
async deregister(serviceId: string): Promise<void> {
await this.consul.agent.service.deregister(serviceId);
console.log(`Service ${serviceId} deregistered`);
}
async discover(serviceName: string): Promise<ServiceInfo[]> {
const services = await this.consul.health.service({
service: serviceName,
passing: true
});
return services.map((service: any) => ({
id: service.Service.ID,
name: service.Service.Service,
address: service.Service.Address,
port: service.Service.Port,
tags: service.Service.Tags,
meta: service.Service.Meta,
health: {
interval: '10s',
timeout: '3s',
deregisterCriticalServiceAfter: '30s'
}
}));
}
async health(serviceId: string): Promise<HealthStatus> {
const health = await this.consul.health.service({
service: serviceId
});
return {
status: health.length > 0 ? 'healthy' : 'unhealthy',
checks: health.map((check: any) => ({
name: check.CheckID,
status: check.Status,
output: check.Output
}))
};
}
}
// 服务启动器
class ServiceBootstrap {
private registry: ServiceRegistry;
private serviceInfo: ServiceInfo;
constructor(registry: ServiceRegistry, serviceInfo: ServiceInfo) {
this.registry = registry;
this.serviceInfo = serviceInfo;
}
async start(): Promise<void> {
// 注册服务
await this.registry.register(this.serviceInfo);
// 设置优雅关闭
this.setupGracefulShutdown();
console.log(`Service ${this.serviceInfo.name} started on ${this.serviceInfo.address}:${this.serviceInfo.port}`);
}
private setupGracefulShutdown(): void {
const shutdown = async (signal: string) => {
console.log(`Received ${signal}, shutting down gracefully...`);
try {
// 注销服务
await this.registry.deregister(this.serviceInfo.id);
console.log('Service deregistered successfully');
// 关闭应用
process.exit(0);
} catch (error) {
console.error('Error during shutdown:', error);
process.exit(1);
}
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
}
}
// 负载均衡器
class LoadBalancer {
private registry: ServiceRegistry;
private cache: Map<string, ServiceInfo[]> = new Map();
private cacheTimeout = 30000; // 30秒缓存
constructor(registry: ServiceRegistry) {
this.registry = registry;
}
async getService(serviceName: string, strategy: 'round-robin' | 'random' | 'least-connections' = 'round-robin'): Promise<ServiceInfo> {
const services = await this.getHealthyServices(serviceName);
if (services.length === 0) {
throw new Error(`No healthy instances found for service ${serviceName}`);
}
switch (strategy) {
case 'round-robin':
return this.roundRobinSelect(serviceName, services);
case 'random':
return this.randomSelect(services);
case 'least-connections':
return this.leastConnectionsSelect(services);
default:
return services[0];
}
}
private async getHealthyServices(serviceName: string): Promise<ServiceInfo[]> {
const cached = this.cache.get(serviceName);
if (cached) {
return cached;
}
const services = await this.registry.discover(serviceName);
this.cache.set(serviceName, services);
// 设置缓存过期
setTimeout(() => {
this.cache.delete(serviceName);
}, this.cacheTimeout);
return services;
}
private roundRobinSelect(serviceName: string, services: ServiceInfo[]): ServiceInfo {
// 简单的轮询实现
const key = `${serviceName}_index`;
let index = (global as any)[key] || 0;
const service = services[index % services.length];
(global as any)[key] = index + 1;
return service;
}
private randomSelect(services: ServiceInfo[]): ServiceInfo {
const index = Math.floor(Math.random() * services.length);
return services[index];
}
private leastConnectionsSelect(services: ServiceInfo[]): ServiceInfo {
// 简化实现,实际应该跟踪连接数
return this.randomSelect(services);
}
}
3.3 数据架构设计
3.3.1 数据模型设计
核心实体关系图
erDiagram
User ||--o{ Project : owns
User ||--o{ Role : has
Role ||--o{ Permission : contains
Project ||--o{ Page : contains
Project ||--o{ ProjectComponent : uses
Page ||--o{ PageComponent : contains
Component ||--o{ ComponentVersion : has
Component ||--o{ ProjectComponent : used_in
Component ||--o{ PageComponent : used_in
ComponentVersion ||--o{ ComponentDependency : depends_on
Workflow ||--o{ WorkflowStep : contains
WorkflowStep ||--o{ Task : generates
Task ||--o{ User : assigned_to
User {
bigint id PK
string username UK
string email UK
string password_hash
string full_name
string avatar_url
enum status
bigint role_id FK
timestamp created_at
timestamp updated_at
}
Project {
bigint id PK
string name
text description
bigint owner_id FK
json config
enum status
string version
timestamp created_at
timestamp updated_at
}
Page {
bigint id PK
bigint project_id FK
string name
string path UK
json config
json meta
timestamp created_at
timestamp updated_at
}
Component {
bigint id PK
string name
string category
string version
json config
json schema
string preview_url
bigint author_id FK
enum status
int download_count
timestamp created_at
timestamp updated_at
}
数据模型定义
// 基础实体接口
interface BaseEntity {
id: number;
createdAt: Date;
updatedAt: Date;
}
// 用户相关实体
interface User extends BaseEntity {
username: string;
email: string;
passwordHash: string;
fullName?: string;
avatarUrl?: string;
status: 'active' | 'inactive' | 'suspended';
roleId?: number;
role?: Role;
lastLoginAt?: Date;
}
interface Role extends BaseEntity {
name: string;
description?: string;
permissions: Permission[];
}
interface Permission {
id: number;
resource: string;
action: string;
conditions?: any;
}
// 项目相关实体
interface Project extends BaseEntity {
name: string;
description?: string;
ownerId: number;
owner?: User;
config?: ProjectConfig;
status: 'draft' | 'published' | 'archived';
version: string;
pages: Page[];
components: ProjectComponent[];
}
interface ProjectConfig {
theme: ThemeConfig;
layout: LayoutConfig;
routing: RoutingConfig;
build: BuildConfig;
deployment: DeploymentConfig;
}
interface Page extends BaseEntity {
projectId: number;
project?: Project;
name: string;
path: string;
config: PageConfig;
meta?: PageMeta;
components: PageComponent[];
}
interface PageConfig {
layout: string;
components: ComponentInstance[];
styles: StyleConfig;
scripts: ScriptConfig[];
seo: SEOConfig;
}
interface PageMeta {
title?: string;
description?: string;
keywords?: string[];
author?: string;
thumbnail?: string;
}
// 组件相关实体
interface Component extends BaseEntity {
name: string;
category: string;
version: string;
config: ComponentConfig;
schema: ComponentSchema;
previewUrl?: string;
authorId?: number;
author?: User;
status: 'draft' | 'published' | 'deprecated';
downloadCount: number;
versions: ComponentVersion[];
dependencies: ComponentDependency[];
}
interface ComponentConfig {
displayName: string;
description: string;
icon: string;
category: string;
tags: string[];
props: PropDefinition[];
events: EventDefinition[];
slots: SlotDefinition[];
styles: StyleDefinition[];
}
interface ComponentSchema {
type: 'object';
properties: Record<string, PropertySchema>;
required?: string[];
additionalProperties?: boolean;
}
interface ComponentVersion extends BaseEntity {
componentId: number;
component?: Component;
version: string;
changelog: string;
config: ComponentConfig;
schema: ComponentSchema;
deprecated: boolean;
}
interface ComponentDependency {
id: number;
componentId: number;
dependencyName: string;
dependencyVersion: string;
type: 'runtime' | 'build';
}
// 组件实例
interface ComponentInstance {
id: string;
componentName: string;
componentVersion: string;
props: Record<string, any>;
styles: Record<string, any>;
events: Record<string, string>;
children?: ComponentInstance[];
slot?: string;
}
// 工作流相关实体
interface Workflow extends BaseEntity {
name: string;
description?: string;
version: string;
definition: WorkflowDefinition;
status: 'draft' | 'published' | 'archived';
authorId: number;
steps: WorkflowStep[];
}
interface WorkflowDefinition {
nodes: WorkflowNode[];
edges: WorkflowEdge[];
variables: WorkflowVariable[];
}
interface WorkflowStep extends BaseEntity {
workflowId: number;
name: string;
type: 'start' | 'task' | 'decision' | 'end';
config: StepConfig;
position: { x: number; y: number };
nextSteps: string[];
}
interface Task extends BaseEntity {
workflowId: number;
stepId: number;
assigneeId?: number;
assignee?: User;
title: string;
description?: string;
status: 'pending' | 'in_progress' | 'completed' | 'rejected';
dueDate?: Date;
completedAt?: Date;
result?: any;
}
3.3.2 数据分片策略
水平分片
// 分片策略接口
interface ShardingStrategy {
getShardKey(entity: any): string;
getShardId(shardKey: string): string;
getAllShards(): string[];
}
// 基于用户ID的分片策略
class UserBasedShardingStrategy implements ShardingStrategy {
private shardCount: number;
private shards: string[];
constructor(shardCount: number = 4) {
this.shardCount = shardCount;
this.shards = Array.from({ length: shardCount }, (_, i) => `shard_${i}`);
}
getShardKey(entity: any): string {
// 根据用户ID或所有者ID确定分片键
const userId = entity.userId || entity.ownerId || entity.id;
return userId.toString();
}
getShardId(shardKey: string): string {
const hash = this.hashCode(shardKey);
const shardIndex = Math.abs(hash) % this.shardCount;
return this.shards[shardIndex];
}
getAllShards(): string[] {
return [...this.shards];
}
private hashCode(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return hash;
}
}
// 基于时间的分片策略
class TimeBasedShardingStrategy implements ShardingStrategy {
private timeUnit: 'month' | 'quarter' | 'year';
constructor(timeUnit: 'month' | 'quarter' | 'year' = 'month') {
this.timeUnit = timeUnit;
}
getShardKey(entity: any): string {
const date = entity.createdAt || new Date();
return this.formatDate(date);
}
getShardId(shardKey: string): string {
return `shard_${shardKey}`;
}
getAllShards(): string[] {
// 返回所有可能的时间分片
const shards: string[] = [];
const now = new Date();
const startYear = 2024;
for (let year = startYear; year <= now.getFullYear(); year++) {
if (this.timeUnit === 'year') {
shards.push(`shard_${year}`);
} else if (this.timeUnit === 'quarter') {
for (let quarter = 1; quarter <= 4; quarter++) {
shards.push(`shard_${year}Q${quarter}`);
}
} else {
for (let month = 1; month <= 12; month++) {
shards.push(`shard_${year}${month.toString().padStart(2, '0')}`);
}
}
}
return shards;
}
private formatDate(date: Date): string {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const quarter = Math.ceil(month / 3);
switch (this.timeUnit) {
case 'year':
return year.toString();
case 'quarter':
return `${year}Q${quarter}`;
case 'month':
return `${year}${month.toString().padStart(2, '0')}`;
default:
return year.toString();
}
}
}
// 分片管理器
class ShardManager {
private strategies: Map<string, ShardingStrategy> = new Map();
private connections: Map<string, any> = new Map();
constructor() {
this.initializeStrategies();
}
private initializeStrategies(): void {
// 用户相关表使用用户分片策略
const userStrategy = new UserBasedShardingStrategy(4);
this.strategies.set('users', userStrategy);
this.strategies.set('projects', userStrategy);
this.strategies.set('pages', userStrategy);
// 日志相关表使用时间分片策略
const timeStrategy = new TimeBasedShardingStrategy('month');
this.strategies.set('audit_logs', timeStrategy);
this.strategies.set('access_logs', timeStrategy);
this.strategies.set('performance_metrics', timeStrategy);
}
getConnection(tableName: string, entity: any): any {
const strategy = this.strategies.get(tableName);
if (!strategy) {
// 如果没有分片策略,使用默认连接
return this.connections.get('default');
}
const shardKey = strategy.getShardKey(entity);
const shardId = strategy.getShardId(shardKey);
return this.connections.get(shardId) || this.connections.get('default');
}
async queryAllShards(tableName: string, query: any): Promise<any[]> {
const strategy = this.strategies.get(tableName);
if (!strategy) {
const connection = this.connections.get('default');
return await connection.query(query);
}
const shards = strategy.getAllShards();
const promises = shards.map(async (shardId) => {
const connection = this.connections.get(shardId);
if (connection) {
try {
return await connection.query(query);
} catch (error) {
console.error(`Error querying shard ${shardId}:`, error);
return [];
}
}
return [];
});
const results = await Promise.all(promises);
return results.flat();
}
addConnection(shardId: string, connection: any): void {
this.connections.set(shardId, connection);
}
addStrategy(tableName: string, strategy: ShardingStrategy): void {
this.strategies.set(tableName, strategy);
}
}
3.3.3 缓存策略
多级缓存架构
// 缓存层级定义
interface CacheLayer {
name: string;
ttl: number;
maxSize?: number;
evictionPolicy: 'LRU' | 'LFU' | 'FIFO';
}
// 缓存策略配置
interface CacheStrategy {
layers: CacheLayer[];
writeThrough: boolean;
writeBack: boolean;
readThrough: boolean;
}
// 多级缓存管理器
class MultiLevelCacheManager {
private caches: Map<string, any> = new Map();
private strategies: Map<string, CacheStrategy> = new Map();
constructor() {
this.initializeCaches();
this.initializeStrategies();
}
private initializeCaches(): void {
// L1: 内存缓存 (最快,容量最小)
this.caches.set('memory', new Map());
// L2: Redis缓存 (快速,容量中等)
this.caches.set('redis', redisManager.getClient('cache'));
// L3: 数据库缓存 (慢速,容量最大)
this.caches.set('database', null); // 实际数据库连接
}
private initializeStrategies(): void {
// 用户信息缓存策略
this.strategies.set('user', {
layers: [
{ name: 'memory', ttl: 300, maxSize: 1000, evictionPolicy: 'LRU' },
{ name: 'redis', ttl: 1800, evictionPolicy: 'LRU' }
],
writeThrough: true,
writeBack: false,
readThrough: true
});
// 组件信息缓存策略
this.strategies.set('component', {
layers: [
{ name: 'memory', ttl: 600, maxSize: 500, evictionPolicy: 'LFU' },
{ name: 'redis', ttl: 3600, evictionPolicy: 'LRU' }
],
writeThrough: true,
writeBack: false,
readThrough: true
});
// 页面配置缓存策略
this.strategies.set('page', {
layers: [
{ name: 'memory', ttl: 180, maxSize: 200, evictionPolicy: 'LRU' },
{ name: 'redis', ttl: 900, evictionPolicy: 'LRU' }
],
writeThrough: false,
writeBack: true,
readThrough: true
});
}
async get<T>(category: string, key: string): Promise<T | null> {
const strategy = this.strategies.get(category);
if (!strategy) {
return null;
}
// 从最快的缓存层开始查找
for (const layer of strategy.layers) {
const cache = this.caches.get(layer.name);
if (!cache) continue;
try {
const value = await this.getFromCache(cache, key, layer.name);
if (value !== null) {
// 如果在较慢的层找到数据,回填到较快的层
await this.backfillCache(category, key, value, layer.name);
return value;
}
} catch (error) {
console.error(`Error reading from cache layer ${layer.name}:`, error);
}
}
// 如果所有缓存层都没有数据,且启用了readThrough,从数据源读取
if (strategy.readThrough) {
const value = await this.readFromDataSource(category, key);
if (value !== null) {
await this.set(category, key, value);
return value;
}
}
return null;
}
async set(category: string, key: string, value: any): Promise<void> {
const strategy = this.strategies.get(category);
if (!strategy) {
return;
}
// 写入所有缓存层
const promises = strategy.layers.map(async (layer) => {
const cache = this.caches.get(layer.name);
if (cache) {
try {
await this.setToCache(cache, key, value, layer);
} catch (error) {
console.error(`Error writing to cache layer ${layer.name}:`, error);
}
}
});
await Promise.all(promises);
// 如果启用了writeThrough,同时写入数据源
if (strategy.writeThrough) {
await this.writeToDataSource(category, key, value);
}
}
async delete(category: string, key: string): Promise<void> {
const strategy = this.strategies.get(category);
if (!strategy) {
return;
}
// 从所有缓存层删除
const promises = strategy.layers.map(async (layer) => {
const cache = this.caches.get(layer.name);
if (cache) {
try {
await this.deleteFromCache(cache, key, layer.name);
} catch (error) {
console.error(`Error deleting from cache layer ${layer.name}:`, error);
}
}
});
await Promise.all(promises);
}
private async getFromCache(cache: any, key: string, layerName: string): Promise<any> {
if (layerName === 'memory') {
return cache.get(key) || null;
} else if (layerName === 'redis') {
const value = await cache.get(key);
return value ? JSON.parse(value) : null;
}
return null;
}
private async setToCache(cache: any, key: string, value: any, layer: CacheLayer): Promise<void> {
if (layer.name === 'memory') {
// 实现LRU淘汰策略
if (layer.maxSize && cache.size >= layer.maxSize) {
const firstKey = cache.keys().next().value;
cache.delete(firstKey);
}
cache.set(key, value);
// 设置过期时间
setTimeout(() => {
cache.delete(key);
}, layer.ttl * 1000);
} else if (layer.name === 'redis') {
await cache.setex(key, layer.ttl, JSON.stringify(value));
}
}
private async deleteFromCache(cache: any, key: string, layerName: string): Promise<void> {
if (layerName === 'memory') {
cache.delete(key);
} else if (layerName === 'redis') {
await cache.del(key);
}
}
private async backfillCache(category: string, key: string, value: any, foundLayer: string): Promise<void> {
const strategy = this.strategies.get(category);
if (!strategy) return;
// 回填到比当前层更快的所有层
const foundIndex = strategy.layers.findIndex(layer => layer.name === foundLayer);
const layersToBackfill = strategy.layers.slice(0, foundIndex);
for (const layer of layersToBackfill) {
const cache = this.caches.get(layer.name);
if (cache) {
try {
await this.setToCache(cache, key, value, layer);
} catch (error) {
console.error(`Error backfilling cache layer ${layer.name}:`, error);
}
}
}
}
private async readFromDataSource(category: string, key: string): Promise<any> {
// 实际从数据库或其他数据源读取数据
// 这里需要根据具体的数据源实现
console.log(`Reading ${key} from data source for category ${category}`);
return null;
}
private async writeToDataSource(category: string, key: string, value: any): Promise<void> {
// 实际写入数据库或其他数据源
console.log(`Writing ${key} to data source for category ${category}`);
}
}
// 缓存装饰器
function Cacheable(category: string, keyGenerator?: (args: any[]) => string) {
return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {
const method = descriptor.value;
descriptor.value = async function (...args: any[]) {
const cacheManager = new MultiLevelCacheManager();
const key = keyGenerator ? keyGenerator(args) : `${propertyName}_${JSON.stringify(args)}`;
// 尝试从缓存获取
let result = await cacheManager.get(category, key);
if (result === null) {
// 缓存未命中,执行原方法
result = await method.apply(this, args);
// 将结果存入缓存
if (result !== null && result !== undefined) {
await cacheManager.set(category, key, result);
}
}
return result;
};
};
}
// 使用示例
class UserService {
@Cacheable('user', (args) => `user_${args[0]}`)
async getUserById(userId: string): Promise<User | null> {
// 实际的数据库查询逻辑
console.log(`Fetching user ${userId} from database`);
return null; // 实际实现
}
@Cacheable('user', (args) => `user_profile_${args[0]}`)
async getUserProfile(userId: string): Promise<UserProfile | null> {
console.log(`Fetching user profile ${userId} from database`);
return null; // 实际实现
}
}
3.4 安全架构设计
3.4.1 身份认证与授权
JWT认证机制
// JWT配置接口
interface JWTConfig {
secret: string;
accessTokenExpiry: string;
refreshTokenExpiry: string;
issuer: string;
audience: string;
}
// JWT服务
class JWTService {
private config: JWTConfig;
constructor(config: JWTConfig) {
this.config = config;
}
generateTokens(user: User): TokenPair {
const payload = {
sub: user.id.toString(),
username: user.username,
email: user.email,
role: user.role?.name,
permissions: user.role?.permissions || []
};
const accessToken = jwt.sign(payload, this.config.secret, {
expiresIn: this.config.accessTokenExpiry,
issuer: this.config.issuer,
audience: this.config.audience
});
const refreshToken = jwt.sign(
{ sub: user.id.toString(), type: 'refresh' },
this.config.secret,
{
expiresIn: this.config.refreshTokenExpiry,
issuer: this.config.issuer,
audience: this.config.audience
}
);
return { accessToken, refreshToken };
}
verifyToken(token: string): JWTPayload {
try {
return jwt.verify(token, this.config.secret, {
issuer: this.config.issuer,
audience: this.config.audience
}) as JWTPayload;
} catch (error) {
throw new Error('Invalid token');
}
}
refreshAccessToken(refreshToken: string): string {
const payload = this.verifyToken(refreshToken);
if (payload.type !== 'refresh') {
throw new Error('Invalid refresh token');
}
// 生成新的访问令牌
const newPayload = {
sub: payload.sub,
username: payload.username,
email: payload.email,
role: payload.role,
permissions: payload.permissions
};
return jwt.sign(newPayload, this.config.secret, {
expiresIn: this.config.accessTokenExpiry,
issuer: this.config.issuer,
audience: this.config.audience
});
}
}
interface TokenPair {
accessToken: string;
refreshToken: string;
}
interface JWTPayload {
sub: string;
username: string;
email: string;
role: string;
permissions: Permission[];
type?: string;
iat: number;
exp: number;
}
RBAC权限模型
// 权限模型定义
interface Permission {
resource: string;
action: string;
conditions?: PermissionCondition[];
}
interface PermissionCondition {
field: string;
operator: 'eq' | 'ne' | 'in' | 'nin' | 'gt' | 'lt' | 'contains';
value: any;
}
interface Role {
id: number;
name: string;
description?: string;
permissions: Permission[];
inherits?: Role[];
}
// 权限检查器
class PermissionChecker {
private roles: Map<string, Role> = new Map();
constructor() {
this.initializeRoles();
}
private initializeRoles(): void {
// 定义基础角色
const guestRole: Role = {
id: 1,
name: 'guest',
description: '访客用户',
permissions: [
{ resource: 'component', action: 'read' },
{ resource: 'template', action: 'read' }
]
};
const userRole: Role = {
id: 2,
name: 'user',
description: '普通用户',
permissions: [
{ resource: 'project', action: 'create' },
{ resource: 'project', action: 'read', conditions: [{ field: 'ownerId', operator: 'eq', value: '${user.id}' }] },
{ resource: 'project', action: 'update', conditions: [{ field: 'ownerId', operator: 'eq', value: '${user.id}' }] },
{ resource: 'project', action: 'delete', conditions: [{ field: 'ownerId', operator: 'eq', value: '${user.id}' }] },
{ resource: 'page', action: 'create' },
{ resource: 'page', action: 'read' },
{ resource: 'page', action: 'update' },
{ resource: 'page', action: 'delete' },
{ resource: 'component', action: 'read' },
{ resource: 'component', action: 'install' }
],
inherits: [guestRole]
};
const adminRole: Role = {
id: 3,
name: 'admin',
description: '管理员',
permissions: [
{ resource: '*', action: '*' }
],
inherits: [userRole]
};
this.roles.set('guest', guestRole);
this.roles.set('user', userRole);
this.roles.set('admin', adminRole);
}
hasPermission(userRole: string, resource: string, action: string, context?: any): boolean {
const role = this.roles.get(userRole);
if (!role) {
return false;
}
return this.checkRolePermission(role, resource, action, context);
}
private checkRolePermission(role: Role, resource: string, action: string, context?: any): boolean {
// 检查直接权限
for (const permission of role.permissions) {
if (this.matchesPermission(permission, resource, action, context)) {
return true;
}
}
// 检查继承的权限
if (role.inherits) {
for (const inheritedRole of role.inherits) {
if (this.checkRolePermission(inheritedRole, resource, action, context)) {
return true;
}
}
}
return false;
}
private matchesPermission(permission: Permission, resource: string, action: string, context?: any): boolean {
// 检查资源匹配
if (permission.resource !== '*' && permission.resource !== resource) {
return false;
}
// 检查操作匹配
if (permission.action !== '*' && permission.action !== action) {
return false;
}
// 检查条件
if (permission.conditions && context) {
return this.evaluateConditions(permission.conditions, context);
}
return true;
}
private evaluateConditions(conditions: PermissionCondition[], context: any): boolean {
return conditions.every(condition => {
const contextValue = this.getContextValue(context, condition.field);
const conditionValue = this.resolveValue(condition.value, context);
switch (condition.operator) {
case 'eq':
return contextValue === conditionValue;
case 'ne':
return contextValue !== conditionValue;
case 'in':
return Array.isArray(conditionValue) && conditionValue.includes(contextValue);
case 'nin':
return Array.isArray(conditionValue) && !conditionValue.includes(contextValue);
case 'gt':
return contextValue > conditionValue;
case 'lt':
return contextValue < conditionValue;
case 'contains':
return String(contextValue).includes(String(conditionValue));
default:
return false;
}
});
}
private getContextValue(context: any, field: string): any {
const parts = field.split('.');
let value = context;
for (const part of parts) {
value = value?.[part];
}
return value;
}
private resolveValue(value: any, context: any): any {
if (typeof value === 'string' && value.startsWith('${') && value.endsWith('}')) {
const expression = value.slice(2, -1);
return this.getContextValue(context, expression);
}
return value;
}
}
3.4.2 数据安全
数据加密
// 加密服务
class EncryptionService {
private algorithm = 'aes-256-gcm';
private keyLength = 32;
private ivLength = 16;
private tagLength = 16;
constructor(private secretKey: string) {
if (secretKey.length !== this.keyLength) {
throw new Error(`Secret key must be ${this.keyLength} bytes long`);
}
}
encrypt(plaintext: string): EncryptedData {
const iv = crypto.randomBytes(this.ivLength);
const cipher = crypto.createCipher(this.algorithm, this.secretKey);
cipher.setAAD(Buffer.from('lowcode-platform'));
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag();
return {
encrypted,
iv: iv.toString('hex'),
tag: tag.toString('hex')
};
}
decrypt(encryptedData: EncryptedData): string {
const decipher = crypto.createDecipher(this.algorithm, this.secretKey);
decipher.setAAD(Buffer.from('lowcode-platform'));
decipher.setAuthTag(Buffer.from(encryptedData.tag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, 12);
}
verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
generateSecureToken(length: number = 32): string {
return crypto.randomBytes(length).toString('hex');
}
}
interface EncryptedData {
encrypted: string;
iv: string;
tag: string;
}
3.5 小结
本章详细介绍了低代码平台的架构设计,包括:
核心要点
- 整体架构:采用分层架构设计,包括表现层、网关层、业务层、数据层和基础设施层
- 微服务架构:基于领域驱动设计拆分服务,实现松耦合和高内聚
- 数据架构:设计合理的数据模型,实现数据分片和多级缓存
- 安全架构:实现完整的身份认证、授权和数据安全机制
设计原则
- 可扩展性:支持水平和垂直扩展,采用微服务架构
- 可维护性:模块化设计,职责单一,代码质量高
- 高性能:多级缓存,数据库优化,CDN加速
- 安全性:多因素认证,细粒度权限控制,数据加密
- 易用性:直观的界面设计,响应式布局,无障碍访问
技术选型
- 微服务通信:HTTP/REST同步通信,消息队列异步通信
- 服务发现:Consul服务注册与发现,负载均衡
- 数据存储:MySQL主数据库,Redis缓存,分片策略
- 安全机制:JWT认证,RBAC权限模型,数据加密
架构优势
- 高可用性:多实例部署,故障转移,服务降级
- 高并发:负载均衡,缓存优化,异步处理
- 易扩展:微服务架构,水平扩展,插件化设计
- 易维护:清晰的服务边界,完善的监控和日志
下一章我们将深入学习可视化设计器的实现,了解如何构建一个功能强大、易用的拖拽式页面设计器。