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#
graph LR
Clients["fa:fa-globe Clients<br/>Web / Mobile"]
Gateway["fa:fa-shield-halved API Gateway<br/>Express"]
Services["fa:fa-puzzle-piece Services<br/>Plugins"]
Queue["fa:fa-list-check Message Queue<br/>RabbitMQ + Redis"]
DB["fa:fa-database Database<br/>PostgreSQL"]
Clients --> Gateway --> Services
Gateway --> Queue
Services --> DB
style Clients fill:#e8f3ff,stroke:#568aff,color:#0a155c
style Gateway fill:#e8f3ff,stroke:#568aff,color:#0a155c
style Services fill:#e8f3ff,stroke:#568aff,color:#0a155c
style Queue fill:#f5f5f5,stroke:#d4d4d4,color:#404040
style DB fill:#f5f5f5,stroke:#d4d4d4,color:#404040
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
- Playbook Service: Handles playbook-based workflows and automation
- Plugin Manager Service: Connects to external platforms via plugin instances
- Analytics Service: Processes and stores metrics
3. Plugin System#
Hay's extensibility mechanism:
Plugins are defined using defineHayPlugin() from @hay/plugin-sdk. The plugin contract is HayPluginManifest in /server/types/plugin-sdk.types.ts, exposing capabilities via a runtime /metadata endpoint and interacting with the platform via HayGlobalContext.
Each plugin can:
- Register event listeners
- Extend the API
- Add new UI components
- Access core services
4. Real-Time & Background Messaging#
There is no single event bus module. Real-time events are published to Redis pub/sub channels via ConversationEventsService. Background processing tasks are queued via RabbitMQ (rabbitmqService) and a Redis-backed JobQueueService.
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:
graph LR
A["fa:fa-browser Client Cache"] --> B["fa:fa-cloud CDN"] --> C["fa:fa-bolt Redis"] --> D["fa:fa-database Database"]
style A fill:#e8f3ff,stroke:#568aff,color:#0a155c
style B fill:#e8f3ff,stroke:#568aff,color:#0a155c
style C fill:#e8f3ff,stroke:#568aff,color:#0a155c
style D fill:#f5f5f5,stroke:#d4d4d4,color:#404040
- Client: Browser cache for static assets
- CDN: Configurable asset-domain URL helper for serving static assets from a separate domain, not an integrated CDN caching layer
- Redis: In-memory cache for hot data
- Database: Source of truth
Message Queue#
RabbitMQ (via amqplib) handles orchestrator messaging, and a custom Postgres-backed job queue (using SKIP LOCKED) coordinated through Redis pub/sub handles background jobs:
- Failed jobs are marked as
FAILEDbyJobQueueService.failJob(); there is no automatic retry - Job priority is ordered via a SQL column, not a Bull-style priority queue
- No 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({ conversationId: '123', action: 'create', duration: 45 }, 'Processing conversation');
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