# `Accrue.Storage`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v0.3.0/lib/accrue/storage.ex#L1)

Behaviour + facade for pluggable PDF / asset storage.

v1.0 ships `Accrue.Storage.Null` only — all three callbacks are
no-ops: `put/3` echoes the key back, `get/1` and `delete/1` return
`{:error, :not_configured}`. `Accrue.Storage.Filesystem` is deferred
to v1.1. Hosts needing S3 (or any other backend) write a custom
adapter implementing the three callbacks below and set
`config :accrue, :storage_adapter, MyApp.Storage.S3`.

## Telemetry

`[:accrue, :storage, :put | :get | :delete, :start | :stop | :exception]`
is emitted via `Accrue.Telemetry.span/3` with metadata
`%{adapter: module, key: binary, bytes: non_neg_integer}` for `put`
(bytes omitted on get/delete). Raw binary bodies are NEVER placed in
metadata — `:bytes` is a scalar `byte_size/1` of the payload only.

## Key scheme

Keys are library-derived binaries (e.g., `"invoices/<id>.pdf"`) —
never user input in v1.0. The future `Filesystem` adapter (v1.1) MUST
add a path-normalization guard against traversal.

# `key`

```elixir
@type key() :: String.t()
```

# `meta`

```elixir
@type meta() :: map()
```

# `delete`

```elixir
@callback delete(key()) :: :ok | {:error, term()}
```

# `get`

```elixir
@callback get(key()) :: {:ok, binary()} | {:error, term()}
```

# `put`

```elixir
@callback put(key(), binary(), meta()) :: {:ok, key()} | {:error, term()}
```

# `delete`

```elixir
@spec delete(key()) :: :ok | {:error, term()}
```

Deletes the binary stored at `key` via the configured adapter.
`Null` always returns `{:error, :not_configured}`.

# `get`

```elixir
@spec get(key()) :: {:ok, binary()} | {:error, term()}
```

Fetches the binary stored at `key` via the configured adapter.
`Null` always returns `{:error, :not_configured}`.

# `put`

```elixir
@spec put(key(), binary(), meta()) :: {:ok, key()} | {:error, term()}
```

Stores `binary` at `key` via the configured adapter. Returns the
canonical key on success (may differ from the input for adapters
that apply transforms; `Null` echoes untouched).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
