Skip to main content
Arius is built around a three-layer architecture that separates user interaction from business logic and infrastructure. Every command flows through a lightweight frontend (CLI or desktop UI), into a core business logic layer, and then out to one or more infrastructure backends.

Layer diagram

┌─────────────────────────────────────────────────────────────────────┐
│                         User Interaction                            │
│                    (CLI Terminal or WPF UI)                         │
└──────────────────────────┬──────────────────────────────────────────┘

              ┌────────────┴───────────┐
              │                        │
              ▼                        ▼
    ┌──────────────────┐    ┌──────────────────┐
    │   Arius.Cli      │    │ Arius.Explorer   │
    │   (CliFx)        │    │   (WPF/MVVM)     │
    └────────┬─────────┘    └────────┬─────────┘
             │                       │
             └───────────┬───────────┘
                         │  IMediator.Send()

              ┌────────────────────┐
              │   Arius.Core       │
              │   (Business Logic) │
              │                    │
              │  - Validators      │
              │  - Handlers        │
              │  - Domain Models   │
              └─────────┬──────────┘

        ┌───────────────┼───────────────┐
        │               │               │
        ▼               ▼               ▼
┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│   SQLite    │  │  Azure Blob │  │  Local File │
│ (Metadata)  │  │  (Storage)  │  │   System    │
└─────────────┘  └─────────────┘  └─────────────┘

Layer responsibilities

LayerProjectsRole
PresentationArius.Cli, Arius.ExplorerParse user input, display progress, dispatch commands via IMediator
Business logicArius.CoreValidate commands, orchestrate pipelines, enforce domain rules
InfrastructureAzure Blob Storage, SQLite, Local FSPersist and retrieve data
The presentation layer never calls infrastructure directly. All communication between layers goes through IMediator.Send(), keeping the CLI and WPF projects thin and testable.

Architecture principles

1. Vertical Slice Architecture

Each feature lives in its own folder inside Arius.Core/Features/. The command definition, handler, and validator are co-located, so adding or changing a feature does not require touching unrelated code.
Features/
├── Commands/
│   ├── Archive/          # ArchiveCommand, ArchiveCommandHandler, ArchiveCommandValidator
│   └── Restore/          # RestoreCommand, RestoreCommandHandler, RestoreCommandValidator
└── Queries/
    ├── ContainerNames/   # ContainerNamesQuery, ContainerNamesQueryHandler
    └── PointerFileEntries/ # PointerFileEntriesQuery, PointerFileEntriesQueryHandler

2. CQRS

Operations are split into commands (writes) and queries (reads):
  • CommandsArchive, Restore: mutate state and produce side effects.
  • QueriesContainerNames, PointerFileEntries: return data without side effects.
This separation makes the intent of each operation explicit and allows independent optimization.

3. Mediator pattern

Arius.Cli and Arius.Explorer dispatch work by calling IMediator.Send(). Neither project holds a direct reference to any handler. This decoupling means handlers can be tested in isolation and the same handler is reachable from both frontends without duplication.

4. Domain-Driven Design

Core domain concepts are modelled as first-class types:
  • Value objects: Hash (immutable SHA256 wrapper), FilePair (pointer + binary file pair).
  • Entities: tracked with identity through the state repository.
  • Rich domain models: business rules live in the domain layer, not in handlers or controllers.

HandlerContext pattern

Every handler receives an immutable HandlerContext record that bundles all validated dependencies for the operation. A HandlerContextBuilder initialises and validates the context before the handler runs.
┌─────────────┐
│   Command   │  (e.g., ArchiveCommand)
└──────┬──────┘


┌──────────────────────┐
│ HandlerContextBuilder│  Build context with dependencies
│  - Validate command  │
│  - Init Azure Blob   │
│  - Setup StateRepo   │
│  - Config FileSystem │
└──────┬───────────────┘


┌──────────────────────┐
│   HandlerContext     │  Immutable record with:
│  (Immutable Record)  │  - Command/Query
│                      │  - ArchiveStorage (Azure + Encryption)
│                      │  - StateRepository (SQLite)
│                      │  - FilePairFileSystem (Zio)
│                      │  - Hasher (SHA256)
└──────┬───────────────┘


┌─────────────────┐
│  Command Handler│  Business logic using context
└──────┬──────────┘

       ├─────▶ context.FileSystem      ──────▶  Local File Operations
       ├─────▶ context.StateRepository ──────▶  SQLite
       ├─────▶ context.ArchiveStorage  ──────▶  Azure Blob Storage
       └─────▶ context.Hasher          ──────▶  SHA256 Hash calculation
This pattern separates complex initialisation logic from business logic and makes handlers easy to unit-test by injecting a pre-built context.

Technology stack

TechnologyRole
.NET 10Runtime and base class libraries
CliFxDeclarative CLI command parsing in Arius.Cli
Spectre.ConsoleRich terminal output and progress rendering
Azure.Storage.BlobsAzure Blob Storage client
SQLite / EF CoreLocal state repository and metadata persistence
ZioFilesystem abstraction layer (FilePairFileSystem)
FluentValidationCommand and query validators
MediatorIn-process IMediator implementation (no external bus)
CommunityToolkit.MvvmMVVM helpers for Arius.Explorer
SerilogStructured logging
xUnit / NSubstitute / ShouldlyTesting

Explore further

Archive pipeline

Multi-stage parallel pipeline: indexing, hashing, uploading large files, and TAR-batching small files.

Storage layer

How AzureBlobStorage and EncryptedCompressedStorage compose to deliver encrypted, compressed blob storage.

State repository

SQLite-backed metadata store: schema, change tracking, and the four core types.

Build docs developers (and LLMs) love