System Architecture Overview¶
SPOT uses a microservices architecture with pluggable analyzers and workflow-based orchestration.
High-Level Architecture¶
graph TB
Client[Users, dashboard, CLI]
Retriever[Mail retrievers]
Gateway[API Gateway<br/>:8001]
MO[Mail Orchestrator]
AO[Analyzer Orchestrator]
KS[Knowledge service]
A1[Analyzers]
CP[Context providers]
R1[Responders]
DB[(PostgreSQL)]
Redis[(Redis)]
RMQ[RabbitMQ]
Client -->|raw message| Gateway
Retriever -->|POST /internal/ingest| Gateway
Gateway -->|parse, store raw + view| DB
Gateway -->|email id| MO
Gateway -->|Publish to spot.analysis| RMQ
MO -->|Publish to spot.analysis| RMQ
Gateway -->|Rate limiting, job records| Redis
RMQ -->|Consume from orchestrator.analysis| AO
AO -->|POST /internal/analyze| A1
A1 -->|AnalyzerVerdict| AO
A1 -.->|raw message, parts| Gateway
A1 -.->|query| KS
CP -->|documents| KS
Gateway -->|POST /internal/sync| CP
AO -->|Store Results| DB
AO -->|Publish to spot.results| RMQ
RMQ -->|orchestrator.dispatch| AO
AO -->|POST /internal/respond| R1 Component Overview¶
| Component | Technology | Dependencies | Purpose |
|---|---|---|---|
| API Gateway | FastAPI | RabbitMQ, Redis, PostgreSQL | External API, authentication, intake |
| Analyzer Orchestrator | Python asyncio | RabbitMQ, Redis, PostgreSQL | Workflow execution, verdict policy, responder dispatch |
| Mail Orchestrator | Python asyncio | RabbitMQ, Redis | Queues retrievers' messages, waits for verdicts |
| Knowledge service | FastAPI, pgvector | PostgreSQL, Redis, Ollama | Knowledge Store |
| Plugin Manager | Python | Docker (through a socket proxy) | Runs the plugin containers |
| Plugins | External services | spot-sdk 2 | Analyzers, context providers, mail retrievers, responders |
Core Components¶
API Gateway¶
- Port: 8001 in development;
https://api.DOMAIN, behind Traefik, in a deployment - Technology: FastAPI (Python)
- Responsibilities:
- Authentication & authorization (OAuth2/JWT for users, scoped tokens for plugins)
- Intake: parses each raw message once and stores it, encrypted
- Routing: chooses each email's workflow and its mode (observe or enforce)
- Job submission via RabbitMQ
- Status queries from PostgreSQL and Redis
- Plugin catalog, installer and configuration (
spot.yaml, with its history) - The audit log
Analyzer Orchestrator¶
- Technology: Python asyncio + RabbitMQ
- Responsibilities:
- DAG-based workflow execution
- Analyzer calls over HTTP, with each analyzer's token
- Verdict decided by the workflow's
verdict_policy - Failure handling & retries: a failure is
unknown, never benign - Dispatch of verdicts to responders
- Shadow runs: candidate workflows on production's results, compared with its verdicts
Mail Orchestrator¶
- Technology: Python asyncio
- Responsibilities:
- Receives the emails retrievers ingested, once the API Gateway has stored them
- Publishes them for analysis
- Waits for the verdict when the retriever asks for it
Plugins (Pluggable)¶
- Analyzers: rules, NLP, ML, LLM and MISP analyzers answer a verdict, a score and signals
- Context providers: fill the Knowledge Store (employee directory, ...)
- Mail retrievers: send raw messages from a mail system (the milter, ...)
- Responders: act on verdicts
Infrastructure Services¶
PostgreSQL¶
- Port: 5432 (internal network only)
- Stores: Emails (raw and view, encrypted), analysis results and signals, user accounts, plugin tokens, the Knowledge Store
Redis¶
- Port: 6379 (internal network only)
- Purpose: Rate limiting, job records, plugin catalog, caches
RabbitMQ¶
- Ports: 5672 (AMQP), 15672 (Management UI), internal network only; the api-gateway reaches the Management UI over it
- Exchanges:
spot.analysis(TOPIC) - Job routingspot.results(TOPIC) - Verdicts of finished jobsspot.config(TOPIC) - Configuration reloads- Queues:
orchestrator.analysis- Job consumptionorchestrator.analysis.sync- The ingests of retrievers that wait for their verdictorchestrator.dispatch- Verdicts to dispatch to respondersorchestrator.shadow- Production's results, for the shadow workflowsorchestrator.benchmark- The emails of a platform benchmark run (a backtest)<queue>.dead-letter- The messages each queue parked after its delivery limit
Design Principles¶
1. Separation of Concerns¶
- API Gateway: External interface
- Orchestrators: Business logic
- Analyzers: Specialized analysis
- Infrastructure: Data & messaging
2. Asynchronous Processing¶
- Non-blocking I/O throughout
- RabbitMQ for job distribution
- Polling for status updates
3. Pluggable Architecture¶
- Plugins as independent HTTP services on plugin contract 2 (
spot-sdk2) - Configured in
spot.yamlunderplugins:, by kind
4. Configuration via Environment + YAML¶
- Infrastructure settings and secrets via environment variables
- Platform settings, plugins, workflows and routing via
spot.yaml, on thespot-configvolume; every change is a commit of its history - No database-backed config
Scalability¶
Horizontal Scaling¶
- Plugins: Scale independently based on workload
- API Gateway: Behind load balancer
- Orchestrators: Single instance (workflow consistency)
Vertical Scaling¶
- PostgreSQL: SSD storage, more RAM
- RabbitMQ: Increase connection limits
- Redis: Memory tuning
Security¶
Authentication¶
- OAuth2 with JWT tokens for users and OAuth clients (client credentials)
- A scoped token for each plugin, in both directions
Network Security¶
- Postgres, Redis and RabbitMQ on an internal Docker network with no route out and no host port
- Installed plugins on an internal network (
spot-plugins-isolated) with no route out: they reach the api-gateway, the knowledge service, the analyzer-orchestrator and, through the egress gateway, the hosts their settings name - The analyzer-orchestrator API requires the internal key on every route except
/healthand/version - Only Traefik is exposed: the dashboard and the API Gateway behind it, over TLS. With the
mail-milterprofile, the milter's port too, onRETRIEVER_MILTER_BIND
Next Steps¶
- Services Details - Deep dive into each service
- Data Flow - Request processing flow
- Admin Guide - Deployment and operations