-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
Valerio edited this page Apr 21, 2026
·
3 revisions
Harpyx is split along two orthogonal axes: layers (Clean Architecture) and processes (web-facing vs. background).
┌────────────────────────────────────────────────────────────────┐
│ Presentation │
│ ├── Harpyx.WebApp (Razor Pages + REST API + OpenAPI) │
│ └── Harpyx.Worker (background hosted services) │
├────────────────────────────────────────────────────────────────┤
│ Application │
│ Harpyx.Application — services, DTOs, interfaces, │
│ telemetry sources, domain rules │
├────────────────────────────────────────────────────────────────┤
│ Domain │
│ Harpyx.Domain — entities, enums, no framework deps │
├────────────────────────────────────────────────────────────────┤
│ Infrastructure │
│ Harpyx.Infrastructure — EF Core, MinIO, RabbitMQ, Redis, │
│ OpenSearch, LLM clients, email, │
│ malware scanner, encryption │
└────────────────────────────────────────────────────────────────┘
-
Harpyx.Domaindepends on nothing. -
Harpyx.Applicationdepends only onHarpyx.Domainand abstractions fromMicrosoft.Extensions.*. -
Harpyx.Infrastructuredepends onHarpyx.DomainandHarpyx.Application; it implements the interfaces declared inApplication.Interfaces. -
Harpyx.WebAppandHarpyx.Workerdepend onHarpyx.Application(for services) andHarpyx.Infrastructure(for DI registration of concrete implementations). They do not referenceHarpyx.Domaindirectly except transitively. -
Harpyx.Sharedholds cross-cutting utilities that are framework-agnostic.
This keeps the business logic independent of the backing infrastructure, so swapping (say) OpenSearch for a different vector store only requires a new implementation of IRagRetrievalService / OpenSearchChunkIndexService — no changes elsewhere.
Two independent processes share the same data plane:
| Process | Concern |
|---|---|
Harpyx.WebApp |
HTTP ingress, authentication, CSRF, rate limiting, uploads, chat, admin UI, REST API |
Harpyx.Worker |
RabbitMQ consumer for ParseDocumentJob, scheduled cleanup for expired projects |
Both processes go through the same configuration override chain (Configuration) and register the infrastructure services via AddHarpyxInfrastructure. What differs is the hosted-services set and the HTTP pipeline.
| Dependency | Used for |
|---|---|
| SQL Server | EF Core persistence: tenants, users, projects, documents, jobs, audit |
| MinIO | S3-compatible blob storage for uploaded documents |
| RabbitMQ | Asynchronous job queue with dead-letter exchange |
| Redis | Idempotency tokens and short-lived caches |
| OpenSearch | Vector + keyword index for RAG chunks |
| ClamAV | On-upload malware scanning (fail-closed by default in production) |
| Microsoft Entra | OIDC identity provider for staff/users |
| Google OAuth | Secondary identity provider |
User ──upload──▶ WebApp ──scan──▶ ClamAV
│
├── blob ──▶ MinIO
│
├── metadata ──▶ SQL Server
│
└── ParseDocumentJob ──▶ RabbitMQ ──▶ Worker
│
extract + chunk + embed │
▼
OpenSearch
│
User ──query──▶ WebApp ──RagRetrievalService──▶ OpenSearch ─┘
│
└── LLM client (Claude / OpenAI / Gemini) ──▶ answer
The step-by-step breakdown lives in RAG Pipeline.
-
Tenant — the top-level isolation boundary. Users belong to tenants through
UserTenantwith aTenantRole. - Workspace — a unit of project grouping within a tenant. Workspaces define default LLM models.
- Project — contains documents, prompts, chat messages. Projects can override the workspace's default chat/RAG/OCR LLM models and have an optional lifetime (auto-expires).
-
Document — a file uploaded to a project; transitions through states
Pending → Processing → Ready | Quarantined | Rejected | Failed. - DocumentChunk — the indexed text fragment produced by the RAG pipeline; stored both in SQL and OpenSearch.
- Job — a persisted record of a background job execution (type, state, attempt count, last error).
-
LlmConnection / LlmModel — shared LLM catalog.
Hostedconnections are managed by admins and can expose OpenAI-compatible/local endpoints;Personalconnections are user BYO credentials for managed cloud providers, AES-256-GCM encrypted at rest. - Subscription / PlanLimit — subscription status + enforced plan caps (projects, documents, LLM features).
- AuditEvent — append-only record of security-relevant events.
See Storage and Persistence for the full schema.
-
src/Harpyx.WebApp/Program.cs — WebApp bootstrap (
ConfigureHarpyxHost→AddHarpyxWebAppServices→ pipeline → DB init). -
src/Harpyx.Worker/Program.cs — Worker bootstrap (
ConfigureHarpyxHost→AddHarpyxWorkerServices). - DI composition:
WebApplicationBuilderExtensions,HostApplicationBuilderExtensions, andServiceCollectionExtensionsunderHarpyx.Infrastructure/Extensions.