# ADR: Improved microdao-daarion Architecture vNext **Дата:** 2026-01-19 **Статус:** Прийнято (Phased Rollout) **Версія:** 1.0 --- ## Контекст Поточний стек (Gateway → Router → Swapper → Memory Layer + NATS) працює для MVP, але має обмеження при масштабуванні на багато нод. Потрібно: 1. Легше масштабувати на багато нод 2. Не "розмити" межі сервісів 3. Зробити приватність/аудит/квоти системними, а не точковими --- ## Рішення: Control Plane + Data Plane Architecture ### Загальна схема ``` ┌─────────────────────────────────────────────────────────────────┐ │ CONTROL PLANE │ │ ┌─────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ │ │ RBAC/PDP │ │ Config │ │ Observability │ │ │ │ Service │ │ Registry │ │ + Audit │ │ │ └─────────────┘ └──────────────┘ └──────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ [Policy Cache + Config Sync] │ ┌─────────────────────────────────────────────────────────────────┐ │ DATA PLANE │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ BFF │ │ Ingest │ │ DAGI │ │ Swapper │ │ │ │ Gateway │───▶│ Service │ │ Router │───▶│ Runtime │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └───────────────┴───────────────┴───────────────┘ │ │ │ │ │ ┌─────────▼─────────┐ │ │ │ NATS Cluster │ │ │ │ (Events + Jobs) │ │ │ └─────────┬─────────┘ │ │ │ │ │ ┌──────────────────────┼──────────────────────┐ │ │ │ │ │ │ │ ┌────▼────┐ ┌─────▼─────┐ ┌─────▼─────┐ │ │ │ Memory │ │ CrewAI │ │ Parser │ │ │ │ Service │ │ Workers │ │ Pipeline │ │ │ └─────────┘ └───────────┘ └───────────┘ │ │ │ │ │ ┌────▼────────────────────────────────────────┐ │ │ │ Postgres │ Qdrant │ Neo4j │ Redis │ S3 │ │ │ └─────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## 1. Control Plane (повільніша, керує правилами) ### 1.1 RBAC/PDP Service - Policy Decision Point — окремий сервіс - Кешований на Data Plane рівні - Обробляє: entitlements, scopes, modes, quotas ### 1.2 Config Registry - Версії системних промптів - Routing rules (версійовані) - Quotas per user/team/agent - Feature flags - Allowlists/blocklists ### 1.3 Observability + Audit - Незмінні журнали (append-only) - Prometheus метрики - Grafana dashboards - Alerting (PagerDuty/Slack) --- ## 2. Data Plane (шлях запиту, низька латентність) ### 2.1 BFF Gateway (замість монолітного Gateway) **Відповідальність:** - Auth, sessions, throttling - Webhook signature verification - Request validation & shaping - Rate limiting (per user/IP/team) - TLS termination **НЕ відповідальність:** - Обробка мультимедіа (винесено в Ingest) - Бізнес-логіка (винесено в Router) ### 2.2 Ingest Service (НОВИЙ) **Відповідальність:** - Прийом файлів (фото/відео/аудіо/документи) - Virus scan / size limits - Upload до Object Storage (S3/MinIO) - Публікація події `attachment.created` **Переваги:** - Gateway не блокується важкими операціями - Формалізований потік: файл → подія → обробка - Outbox pattern для надійності ### 2.3 DAGI Router (stateless) **Залишається:** - Routing rules (версійовані з Config Registry) - Tool registry (дозволені інструменти) - Policy checks (mode/confidential, scopes, budgets) - Privacy Gate (mode-aware middleware) **Виноситься:** - Довгі workflow → CrewAI Workers - Стани задач → NATS + Memory - Проміжні артефакти → Object Storage **Статус:** Повністю stateless, горизонтально масштабується ### 2.4 Swapper Runtime **Відповідальність:** - LLM inference (local/cloud) - Vision processing - OCR - STT/TTS - Image generation - Lazy loading/unloading моделей **Статус:** Capability runtime, не має бізнес-логіки ### 2.5 Memory Service **Відповідальність:** - CRUD для всіх data stores - Інкапсуляція Postgres/Qdrant/Neo4j/Redis - Без бізнес-логіки продукту **3 рівні пам'яті:** | Scope | Qdrant | Neo4j | Postgres | |-------|--------|-------|----------| | **Personal** | `user_{id}_*` collections | `:User` nodes + ACL | `user_facts`, `user_sessions` | | **Team/DAO** | `team_{id}_*` collections | `:Team`, `:Project` nodes | `team_facts`, `team_quotas` | | **Public** | `public_*` collections | `:Public` nodes | `indexed_content` | **Правило:** Індексація plaintext дозволена лише для `scope=public + indexed=true`. Для confidential — тільки шифротекст/метадані. --- ## 3. Async Workers (через NATS) ### 3.1 CrewAI Workers **Позиціонування:** Workflow/Job runtime, НЕ в лінії запиту **Принципи:** - Бере задачі з NATS JetStream - Ідемпотентність (idempotency key) - Пише результат у Memory Service - Повертає статус подією **Синхронно (в лінії запиту):** Тільки короткі задачі (LLM answer ≤ N секунд) **Асинхронно (job):** Все інше ### 3.2 Parser Pipeline **Тригер:** `attachment.created` подія **Потік:** ``` attachment.created → Parser Worker → → extraction/chunking → → артефакти для RAG → → attachment.parsed подія ``` ### 3.3 RAG Indexer **Тригер:** `attachment.parsed` або `content.updated` **Потік:** ``` content.updated → Embeddings → → Qdrant upsert → → content.indexed подія ``` --- ## 4. Privacy Gate (обов'язковий middleware) ### Правило Якщо `mode=confidential`: - Router передає в агентний шар тільки **узагальнений контекст / embedding / features** - Або контент тільки з **явної згоди** - Логи без контенту (тільки метрики) ### Реалізація ```python class PrivacyGate: def check(self, request: Request) -> GateResult: if request.mode == "confidential": if not request.user_consent: return GateResult( allow=False, transform=self.sanitize_context, log_content=False ) return GateResult(allow=True, log_content=True) def sanitize_context(self, context: str) -> str: # Повертає тільки узагальнений summary return summarize(context, max_tokens=100) ``` --- ## 5. NATS Standards ### 5.1 Subject Naming Convention ``` # Messages message.created.{channel_id} message.edited.{channel_id} message.deleted.{channel_id} # Attachments attachment.created.{type} # type: image/video/audio/document attachment.parsed.{type} attachment.indexed.{type} # Agent Operations agent.run.requested.{agent_id} agent.run.started.{agent_id} agent.run.completed.{agent_id} agent.run.failed.{agent_id} # Handoff (orchestration) agent.handoff.requested.{from}.{to} agent.handoff.completed.{from}.{to} # Quota quota.consumed.{user_id} quota.blocked.{user_id} quota.reset.{user_id} # Audit (append-only) audit.{service}.{action} # Ops ops.health.{service} ops.alert.{severity} ``` ### 5.2 Outbox Pattern ```sql CREATE TABLE outbox ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), aggregate_type VARCHAR(255) NOT NULL, aggregate_id VARCHAR(255) NOT NULL, event_type VARCHAR(255) NOT NULL, payload JSONB NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW(), published_at TIMESTAMPTZ, status VARCHAR(20) DEFAULT 'pending' ); CREATE INDEX idx_outbox_pending ON outbox(status, created_at) WHERE status = 'pending'; ``` ### 5.3 Dead Letter Queue (DLQ) - Всі невдалі обробки йдуть у DLQ - Retry policy: exponential backoff - Alert після N retries --- ## 6. Observability: AgentOps Layer ### 6.1 Per-Agent Metrics ```yaml agent_latency_seconds{agent_id, operation} agent_tokens_in_total{agent_id, model} agent_tokens_out_total{agent_id, model} agent_error_rate{agent_id, error_type} agent_tool_calls_total{agent_id, tool} agent_budget_consumed{agent_id, user_id} ``` ### 6.2 Per-Channel Metrics ```yaml channel_rag_hit_rate{channel_id} channel_index_lag_seconds{channel_id} channel_ws_fanout_latency_seconds{channel_id} ``` ### 6.3 Per-Node Metrics ```yaml node_gpu_utilization{node_id, gpu_id} node_vram_used_bytes{node_id, gpu_id} node_queue_lag_seconds{node_id, queue} node_nats_stream_lag{node_id, stream} ``` ### 6.4 Auto-Routing Rules ```yaml # Якщо GPU зайнятий > 80%, переключити на API модель routing_rules: - condition: node_gpu_utilization > 0.8 action: route_to_cloud_llm - condition: agent_error_rate > 0.1 action: fallback_to_backup_agent ``` --- ## 7. Multi-Node Topology ### 7.1 Global Entry ``` gateway.daarion.city (TLS/WAF) │ ▼ [Load Balancer] │ ┌────┴────┐ │ │ Node1 Node2 ... ``` ### 7.2 Per-Node Stack ``` ┌─────────────────────────────────────┐ │ NODE 1 │ │ ┌───────────────────────────────┐ │ │ │ Local Edge Ingress │ │ │ └───────────────────────────────┘ │ │ ┌───────────────────────────────┐ │ │ │ Local DAGI Router │ │ │ └───────────────────────────────┘ │ │ ┌───────────────────────────────┐ │ │ │ Local Swapper (GPU) │ │ │ └───────────────────────────────┘ │ │ ┌───────────────────────────────┐ │ │ │ NATS Leafnode │ │ │ └───────────────────────────────┘ │ │ ┌───────────────────────────────┐ │ │ │ Redis Cache │ │ │ └───────────────────────────────┘ │ └─────────────────────────────────────┘ ``` ### 7.3 Data Layer | Component | Topology | |-----------|----------| | **Postgres** | Primary + Read Replicas (або per-DAO sharding пізніше) | | **Qdrant** | Replication/Sharding | | **Neo4j** | Central + Read Replicas (або domain separation) | | **NATS** | Supercluster / Leafnodes | --- ## 8. Phased Rollout Plan ### Phase 1: Foundation (2-3 тижні) **Пріоритет:** Не ламати MVP - [ ] Створити Config Registry (версії промптів, routing rules) - [ ] Додати Privacy Gate middleware в Router - [ ] Стандартизувати NATS subjects - [ ] Додати Outbox pattern в Memory Service - [ ] AgentOps метрики (базові) ### Phase 2: Separation (3-4 тижні) **Пріоритет:** Розділити responsibilities - [ ] Виділити Ingest Service з Gateway - [ ] Зробити Router повністю stateless - [ ] Винести CrewAI в async workers - [ ] Додати Parser Pipeline - [ ] Audit append-only stream ### Phase 3: Scale (4-6 тижнів) **Пріоритет:** Multi-node готовність - [ ] NATS leafnodes topology - [ ] Per-node stack template (k3s) - [ ] Auto-routing rules (GPU/load based) - [ ] DLQ та retry policies - [ ] Full observability dashboard ### Phase 4: Production (ongoing) - [ ] Load testing - [ ] Chaos engineering - [ ] DR (disaster recovery) runbooks - [ ] SLA monitoring --- ## 9. Migration Notes ### 9.1 Backward Compatibility - Gateway endpoints залишаються незмінними - Внутрішня структура змінюється поступово - Feature flags для поступового rollout ### 9.2 Breaking Changes | Change | Impact | Mitigation | |--------|--------|------------| | Ingest Service | File upload latency | Async processing + webhooks | | Stateless Router | Session state | Move to NATS/Redis | | Async CrewAI | Response time | Progress events + SSE | --- ## 10. Files to Create/Modify ### Нові сервіси: - `/services/ingest/` — Ingest Service - `/services/config-registry/` — Config Registry - `/services/audit/` — Audit Service ### Модифікації: - `/gateway-bot/` → BFF Gateway (спростити) - `/services/router/` → Stateless + Privacy Gate - `/services/swapper/` → Capability Runtime (без змін) - `/services/memory-service/` → + Outbox pattern ### Документація: - `/docs/ADR_ARCHITECTURE_VNEXT.md` — цей документ - `/docs/NATS_SUBJECTS.md` — стандарти subjects - `/docs/PRIVACY_GATE.md` — правила приватності --- ## Альтернативи (відхилені) 1. **Монолітний підхід** — не масштабується 2. **Full microservices одразу** — занадто складно для команди 3. **Serverless (Lambda/Cloud Functions)** — cold start, vendor lock-in --- ## Наслідки ### Позитивні: - Горизонтальне масштабування - Чіткі межі сервісів - Системна приватність та аудит - Multi-node ready ### Негативні: - Більше сервісів = більше operational complexity - Потрібен час на міграцію - Потрібен моніторинг distributed system --- **Версія:** 1.0 **Автор:** Architecture Team **Останнє оновлення:** 2026-01-19