Architecture
Understanding Hay's system architecture and design decisions
System Architecture #
Hay is designed as a modular, event-driven platform that scales with your needs. This document explains the key architectural decisions and how components work together.
High-Level Overview #
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Clients │────▶│ API Gateway │────▶│ Services │
│ (Web/Mobile)│ │ (Express) │ │ (Plugins) │
└─────────────┘ └─────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Message │ │ Database │
│ Queue │ │ (PostgreSQL)│
│ (Bull) │ └─────────────┘
└─────────────┘
Core Components #
1. API Gateway #
The entry point for all client requests:
- Authentication: JWT-based auth with refresh tokens
- Rate Limiting: Prevents abuse and ensures fair usage
- Request Validation: Schema validation using Zod
- Response Formatting: Consistent API responses
2. Service Layer #
Business logic organized as modular services:
- Conversation Service: Manages conversations and messages
- Automation Service: Handles rules and workflows
- Integration Service: Connects to external platforms
- Analytics Service: Processes and stores metrics
3. Plugin System #
Hay's extensibility mechanism:
interface Plugin {
name: string;
version: string;
init: (context: PluginContext) => Promise<void>;
hooks: {
[eventName: string]: HookFunction;
};
}
Each plugin can:
- Register event listeners
- Extend the API
- Add new UI components
- Access core services
4. Event Bus #
Central communication hub:
// Emit an event
eventBus.emit('conversation.created', {
conversationId: '123',
channel: 'email',
customer: { ... }
});
// Listen for events
eventBus.on('conversation.created', async (event) => {
// Handle the event
});
Events flow through the system triggering:
- Automation rules
- Real-time updates
- Analytics tracking
- Plugin hooks
5. Data Layer #
Persistent storage with caching:
- PostgreSQL: Primary data store for conversations, users, settings
- Redis: Caching layer and pub/sub for real-time features
- Object Storage: Attachments and media files
Data Flow #
Incoming Message #
- Message arrives via integration (email, chat, etc.)
- Integration plugin emits
message.receivedevent - Message is validated and stored in database
- Event bus notifies all listeners
- Automation rules are evaluated
- Real-time updates sent to connected clients
Automation Execution #
- Rule trigger conditions evaluated
- If matched, rule added to job queue
- Worker picks up job from queue
- Actions executed in sequence
- Results logged and stored
- Completion event emitted
Scalability Considerations #
Horizontal Scaling #
Hay is designed to scale horizontally:
- Stateless API servers: Scale by adding more instances
- Background workers: Scale job processing independently
- Database read replicas: Distribute read load
Caching Strategy #
Multi-layer caching reduces database load:
Client Cache → CDN → Redis → Database
- Client: Browser cache for static assets
- CDN: Edge caching for global delivery
- Redis: In-memory cache for hot data
- Database: Source of truth
Message Queue #
Bull queue for reliable background processing:
- Retry failed jobs automatically
- Priority queues for urgent tasks
- Rate limiting per job type
- Monitoring and alerting
Security Architecture #
Defense in Depth #
Multiple security layers:
- Network: TLS/SSL encryption for all traffic
- Authentication: JWT with short expiration
- Authorization: Role-based access control (RBAC)
- Input Validation: Sanitize all user input
- Output Encoding: Prevent XSS attacks
- Database: Prepared statements prevent SQL injection
Data Privacy #
- Encryption at rest: Database encryption enabled
- Encryption in transit: TLS 1.3 required
- PII handling: Separate tables with restricted access
- Audit logs: All data access logged
Monitoring and Observability #
Metrics #
Key metrics tracked:
- API response times
- Error rates
- Queue lengths
- Database query performance
- Cache hit rates
Logging #
Structured logging with correlation IDs:
logger.info('Processing conversation', {
correlationId: req.id,
conversationId: '123',
action: 'create',
duration: 45
});
Tracing #
Distributed tracing for debugging:
- Request flows across services
- Performance bottleneck identification
- Error source pinpointing
Next Steps #
- Learn about our development philosophy
- Start building plugins
- Explore the API reference