Architecture
Operyn is built as a Bun + Turborepo monorepo with a modular-monolith backend centered on core-platform, plus a separate ingestion edge service. It follows clean architecture principles: domain logic is framework-free, infrastructure adapters are injected, and asynchronous work is coordinated through BullMQ.
Service Map
| Service | Port | Responsibility |
|---|---|---|
ingestion | 3001 | Accepts log/metric payloads, validates, indexes, and enqueues them |
core-platform | 3003 | Incidents, remediation, notifications, AI diagnosis, team/integration workflows |
dashboard | 3000 | Next.js 15 operations console with real-time incident management |
docs | 3006 | Documentation site (Next.js) |
Data Flow
External Systems (CloudWatch, Prometheus, App Logs)
│
▼
┌─────────────────┐
│ Ingestion │ ← REST API (POST /events/logs, /events/metrics)
│ Service │
│ normalise → │
│ index (OS) → │
│ enqueue (MQ) │
└────────┬────────┘
│ BullMQ
▼
┌──────────────────────────────────────────┐
│ Core Platform │
│ detect → deduplicate → correlate → │
│ diagnose → notify → remediate │
└──────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ Dashboard │ ← SSE + REST
│ (Next.js 15) │ ← Filtering, correlation, team mgmt
└─────────────────┘
Clean Architecture Layers
Each backend module follows a layered structure:
src/
├── domain/ Pure business logic, no framework imports
├── application/ Use cases that orchestrate domain + infrastructure
├── infrastructure/ Framework adapters (database, queue, HTTP clients)
└── interface/ Controllers, guards, DTOs (NestJS layer)
- Domain: defines entities, value objects, and pure functions. Zero dependencies on NestJS, databases, or queues.
- Application: use cases that wire domain logic with infrastructure ports. Injected via constructor.
- Infrastructure: concrete adapters — OpenSearch client, BullMQ producer/consumer, PostgreSQL repositories, and external integration clients.
- Interface: NestJS controllers, guards, and decorators. The thinnest possible layer.
Diagnostic investigations use the same layering: typed tool payloads in interface, policy/rate-limit/scoping in application, and safe connector calls in infrastructure with structured, audited outputs.
Shared Libraries
| Library | Purpose |
|---|---|
@operyn/shared-types | Zod schemas and TypeScript types for all domain events, incidents, remediations, and notifications |
@operyn/connectors | Framework-free adapters: SlackNotifier, JiraClient, K8sClient, AwsDiagnosticsClient, PrometheusClient |
@operyn/ai-orchestrator | LangChain/LangGraph agent pipeline for multi-step AI diagnostic reasoning |
Infrastructure
| Component | Technology | Purpose |
|---|---|---|
| Database | PostgreSQL 16 | Incident and remediation persistence |
| Queue | Redis 7 (BullMQ) | Async event processing and background jobs |
| Search | OpenSearch 2.11 | Log and metric indexing for full-text search |
Design Principles
- Domain isolation — business logic has zero framework dependencies.
- Explicit dependencies — no hidden global state; everything is injected.
- Optional integrations — Slack, Jira, etc. degrade gracefully when unconfigured.
- Event-driven — ingestion and background workflows communicate via BullMQ.
- Typed contracts —
@operyn/shared-typesprovides Zod-validated schemas as the single source of truth.
Authentication
The dashboard owns authentication: it uses better-auth (Next.js API route) for sign-in, sessions, and organization membership. core-platform accepts dashboard JWTs and internal service credentials for background flows. See Authentication and Roles and permissions for details.