> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blobrouter.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> Upload and scanner flows — how the control plane talks to your providers.

<Info>
  **BlobRouter v0.1** · Last updated: August 2026 · Architecture version: **2.0**
</Info>

## Upload path

```text theme={null}
Developer
    │
    ▼
   SDK
    │
    ▼
Cloudflare Worker  (Hono API)
    │
    ▼
Routing Engine     (@blobrouter/core)
    │
    ▼
Router Adapter     (S3-compatible client)
    │
    ▼
AWS S3 / R2 / B2   (presigned PUT/GET — bytes never hit BlobRouter)
```

## Scanner path

```text theme={null}
Dashboard
    │
    ▼
   API
    │
    ▼
 Scanner Worker
    │
    ▼
   STS AssumeRole
    │
    ▼
 Your AWS account  (read-only)
    │
    ▼
Recommendations    (approve before any migration)
```

## Upload flow (detail)

```text theme={null}
1. SDK  → POST /v1/upload/init
2. API  → authenticate API key, load providers, run routing engine
3. API  → decrypt router credentials, mint presigned PUT URL (~1h)
4. API  → insert pending file + routing decision
5. SDK  → PUT bytes directly to provider
6. SDK  → POST /v1/upload/complete
7. API  → HeadObject verify on provider
8. API  → mark file active, record usage_events
```

See [Request lifecycle](/request-lifecycle) for the same path as a single diagram.

## Scanner flow (detail)

```text theme={null}
1. Dashboard → POST /v1/scanner/connect (roleArn, externalId, regions)
2. API → AssumeRole test + ListBuckets
3. Dashboard → POST /v1/scanner/scan
4. API → enqueue Cloudflare Queue job
5. Worker → AssumeRole → list buckets/objects → classify → cost vs optimal
6. Worker → write scan_results, buckets, recommendations
7. Dashboard → GET /v1/scanner/results/:scanId (poll until complete)
```

## Migration flow

```text theme={null}
1. Customer reviews recommendation
2. Dashboard → POST .../recommendations/:id/approve { targetProvider }
3. API → enqueue migration job (only after explicit approve)
4. Worker → copy using router credentials
5. Dashboard → GET /v1/scanner/migration/:id for status
```

Migrations never run automatically.

## Components

| Piece                            | Role                                       |
| -------------------------------- | ------------------------------------------ |
| `@blobrouter/core`               | Routing engine, cost formula, entitlements |
| `@blobrouter/adapters`           | S3 clients + STS scanner                   |
| `apps/api`                       | Control plane on Workers                   |
| `apps/dashboard`                 | Audit UI, providers, savings               |
| `@blobrouter/sdk` / `blobrouter` | Client libraries                           |

## Related

* [Architecture decisions](/decisions/architecture-decisions)
* [How it works](/concepts/how-it-works)
* [Routing logic](/concepts/routing-logic)
* [Security](/security)
