This document provides a comprehensive overview of the Rule Engine architecture, design decisions, and implementation details.
- System Architecture
- Package Structure
- Core Components
- Design Patterns
- Data Flow
- Performance Architecture
- Security Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────────┐ ┌──────────────────┐ ┌───────────────┐ │
│ │ React Apps │ │ Node.js Apps │ │ API Services │ │
│ └────────┬────────┘ └────────┬─────────┘ └───────┬───────┘ │
└───────────┼────────────────────┼─────────────────────┼─────────┘
│ │ │
┌───────────┼────────────────────┼─────────────────────┼─────────┐
│ │ Rule Engine SDK Layer │ │
│ ┌────────▼────────┐ ┌────────▼─────────┐ ┌──────▼───────┐ │
│ │ UI Builder │ │ Rule Engine │ │ Validators │ │
│ │ (@usex/builder)│ │ (@usex/core) │ │ & Utils │ │
│ └─────────────────┘ └──────────────────┘ └──────────────┘ │
└────────────────────────────────────────────────────────────────┘
Rule Engine Core
├── Services
│ ├── RuleEngine # Main evaluation engine
│ ├── Evaluator # Rule evaluation logic
│ ├── Validator # Rule validation
│ ├── Introspector # Rule analysis
│ ├── Builder # Programmatic rule construction
│ └── ObjectDiscovery # JSONPath utilities
│
├── Operators
│ ├── Comparison # Basic comparisons
│ ├── String # String operations
│ ├── Numeric # Number operations
│ ├── Array # Array/collection operations
│ ├── Date/Time # Temporal operations
│ ├── Type # Type validation
│ └── Custom # User-defined operators
│
└── Types & Utils
├── Rule Types # Core type definitions
├── JSONPath Utils # Path resolution
├── Date Utils # Date handling
└── Error Utils # Error management
| Directory | Purpose | Key Contents |
|---|---|---|
/packages/core |
Core rule engine | Engine, operators, types |
/packages/builder |
React UI components | Visual builder, inputs |
/apps/web |
Documentation site | Docs, examples, guides |
/docs |
Project documentation | Architecture, guides |
/scripts |
Build scripts | Automation, tooling |
graph TD
A[@usex/rule-engine-builder] --> B[@usex/rule-engine]
C[React Apps] --> A
D[Node.js Apps] --> B
E[API Services] --> B
// Core Package Exports
export {
// Main Classes
RuleEngine,
ObjectDiscovery,
// Types
RuleType,
Condition,
Constraint,
EvaluationResult,
// Enums
OperatorsType,
ConditionType,
// Utilities
validateRule,
introspectRule,
buildRule
} from '@usex/rule-engine';
// Builder Package Exports
export {
// Components
TreeRuleBuilder,
ModernRuleBuilder,
RuleEvaluator,
HistoryViewer,
// Hooks
useEnhancedRuleStore,
useFieldDiscovery,
useKeyboardShortcuts,
// Types
FieldConfig,
ThemeConfig
} from '@usex/rule-engine-builder';The main service responsible for rule evaluation:
class RuleEngine {
// Singleton instance
private static instance: RuleEngine;
// Mutation system for data preprocessing
private mutations: Map<string, MutationFunction>;
// Cache for performance
private cache: Map<string, any>;
// Core methods
async evaluate<T>(rule: RuleType<T>, criteria: any): Promise<EvaluationResult<T>>;
validate(rule: RuleType<any>): ValidationResult;
introspect(rule: RuleType<any>): IntrospectionResult;
// Static API
static evaluate<T>(...args): Promise<EvaluationResult<T>>;
static validate(...args): ValidationResult;
static builder(): RuleBuilder;
}Input Data → Mutations → Validation → Evaluation → Result
↓ ↓ ↓ ↓ ↓
Criteria Transform Type Check Apply Rules Output
| Layer | Description | Example |
|---|---|---|
| Registration | Operator definition | { name: 'equals', evaluate: (a, b) => a === b } |
| Categorization | Logical grouping | Comparison, String, Numeric, etc. |
| Type Safety | Input/output types | <T>(field: T, value: T) => boolean |
| Validation | Pre-evaluation checks | Value type, range, format |
| Evaluation | Actual comparison | Field value vs constraint value |
Used for operator evaluation:
interface OperatorStrategy {
evaluate(fieldValue: any, constraintValue: any): boolean;
}
class EqualsOperator implements OperatorStrategy {
evaluate(fieldValue: any, constraintValue: any): boolean {
return fieldValue === constraintValue;
}
}
class OperatorFactory {
private strategies: Map<string, OperatorStrategy>;
getOperator(type: string): OperatorStrategy {
return this.strategies.get(type);
}
}For programmatic rule construction:
const rule = RuleEngine.builder()
.add({
and: [
{ field: 'age', operator: 'greater-than', value: 18 },
{ field: 'country', operator: 'equals', value: 'US' }
],
result: { allowed: true }
})
.default({ allowed: false })
.build();Used in the UI for state management:
class RuleStore {
private listeners: Set<() => void> = new Set();
private state: RuleState;
subscribe(listener: () => void) {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
notify() {
this.listeners.forEach(listener => listener());
}
}For undo/redo functionality:
interface Command {
execute(): void;
undo(): void;
}
class UpdateRuleCommand implements Command {
constructor(
private store: RuleStore,
private oldRule: Rule,
private newRule: Rule
) {}
execute() {
this.store.setRule(this.newRule);
}
undo() {
this.store.setRule(this.oldRule);
}
}1. Input Reception
└── Receive rule and criteria
2. Mutation Phase
├── Apply registered mutations
└── Transform criteria data
3. Validation Phase
├── Validate rule structure
├── Check operator validity
└── Verify field paths
4. Resolution Phase
├── Resolve JSONPath expressions
├── Extract field values
└── Handle nested objects
5. Evaluation Phase
├── Apply constraints
├── Evaluate conditions
└── Aggregate results
6. Result Composition
└── Return evaluation result
User Action → Component → Hook → Store → State Update → UI Update
↓ ↓ ↓ ↓ ↓ ↓
Change Handler Action Reducer New State Re-render
| Strategy | Implementation | Impact |
|---|---|---|
| Caching | Memoize evaluation results | 40% faster for repeated rules |
| Lazy Evaluation | Stop on first failure | 60% faster for failing rules |
| Path Optimization | Pre-compile JSONPath | 30% faster path resolution |
| Batch Processing | Evaluate multiple items | 50% throughput increase |
| Trust Mode | Skip validation | 20% faster for trusted rules |
class CacheManager {
private cache: LRUCache<string, any>;
private maxSize: number = 1000;
set(key: string, value: any) {
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
}class BatchEvaluator {
async evaluateBatch<T>(
rule: RuleType<T>,
items: any[],
concurrency: number = 10
): Promise<EvaluationResult<T>[]> {
const chunks = chunk(items, concurrency);
const results = [];
for (const chunk of chunks) {
const chunkResults = await Promise.all(
chunk.map(item => this.evaluate(rule, item))
);
results.push(...chunkResults);
}
return results;
}
}| Layer | Protection | Implementation |
|---|---|---|
| Schema Validation | Rule structure | JSON Schema validation |
| Type Checking | Data types | TypeScript + runtime checks |
| Path Validation | JSONPath safety | Whitelist allowed paths |
| Operator Validation | Valid operators | Operator registry check |
| Value Sanitization | Input cleaning | XSS prevention, type coercion |
class SecurityValidator {
// Prevent prototype pollution
validatePath(path: string): boolean {
const dangerous = ['__proto__', 'constructor', 'prototype'];
return !dangerous.some(d => path.includes(d));
}
// Limit complexity
validateComplexity(rule: RuleType): boolean {
const depth = this.calculateDepth(rule);
const conditions = this.countConditions(rule);
return depth <= MAX_DEPTH && conditions <= MAX_CONDITIONS;
}
// Sanitize regex patterns
validateRegex(pattern: string): boolean {
try {
new RegExp(pattern);
return !pattern.includes('(?<') && // No lookbehind
!pattern.includes('{1000,}'); // No large repetitions
} catch {
return false;
}
}
}interface RuleAccessControl {
canCreate: (user: User) => boolean;
canRead: (user: User, rule: Rule) => boolean;
canUpdate: (user: User, rule: Rule) => boolean;
canDelete: (user: User, rule: Rule) => boolean;
canEvaluate: (user: User, rule: Rule) => boolean;
}
class RuleEngineWithACL extends RuleEngine {
constructor(private acl: RuleAccessControl) {
super();
}
async evaluate(rule: RuleType, criteria: any, user: User) {
if (!this.acl.canEvaluate(user, rule)) {
throw new Error('Access denied');
}
return super.evaluate(rule, criteria);
}
}interface RuleEnginePlugin {
name: string;
version: string;
// Lifecycle hooks
onInit?(engine: RuleEngine): void;
beforeEvaluate?(rule: RuleType, criteria: any): void;
afterEvaluate?(result: EvaluationResult): void;
// Extension points
operators?: Record<string, OperatorDefinition>;
mutations?: Record<string, MutationFunction>;
validators?: Record<string, ValidatorFunction>;
}
class PluginManager {
private plugins: Map<string, RuleEnginePlugin> = new Map();
register(plugin: RuleEnginePlugin) {
this.plugins.set(plugin.name, plugin);
plugin.onInit?.(this.engine);
}
}interface CustomOperator {
name: string;
category: string;
description: string;
// Type constraints
acceptedFieldTypes: FieldType[];
acceptedValueTypes: ValueType[];
// Validation
validate(value: any): ValidationResult;
// Evaluation
evaluate(fieldValue: any, constraintValue: any): boolean;
// UI hints
ui?: {
icon?: string;
color?: string;
inputComponent?: React.ComponentType;
};
}- Distributed Evaluation: Rule evaluation across multiple workers
- Rule Compilation: Compile rules to optimized JavaScript
- Streaming Support: Process data streams with rules
- Edge Computing: Run rules at the edge for low latency
- Plugin Marketplace: Community-contributed operators and plugins
- Rule Templates: Reusable rule patterns
- AI Integration: ML-powered rule suggestions
- Visual Debugging: Step-through rule evaluation
For more technical details, see the API Reference.