# `CMDC.Checkpoint.Backend`
[🔗](https://github.com/tupleyun/cmdc/blob/v0.5.0/lib/cmdc/checkpoint/backend.ex#L1)

Checkpoint 存储后端 behaviour。

让 Checkpoint 在「内存（ETS）/ 轻持久化（DETS）/ 分布式（Postgres 等）」
之间无缝切换。

## 实现指南

- **幂等**：`save/3` 用相同 `checkpoint_id` 多次写入应该是 upsert
- **快**：`load/2` 路径要避免 N+1 查询（必要时缓存 `session_id → 最新 checkpoint_id`）
- **可恢复**：`delete/2` 要能 partial（按 `checkpoint_id`）或 full（按 `session_id`）

## 内置实现

| Backend | 用途 | 持久化 | 跨节点 |
|---|---|---|---|
| `CMDC.Checkpoint.Backend.ETS` | 默认，开发 / 短会话 | ❌ BEAM 重启丢 | ❌ |
| `CMDC.Checkpoint.Backend.DETS` | 单节点持久化 | ✅ 磁盘 | ❌ |
| `CMDC.Checkpoint.Backend.Postgres` *(cmdc_memory_pg)* | 生产 / 分布式 | ✅ DB | ✅ |

# `opts`

```elixir
@type opts() :: keyword()
```

Backend 配置 opts（每个实现自定义字段）。

# `delete`

```elixir
@callback delete(session_id :: String.t(), opts :: opts()) :: :ok | {:error, term()}
```

删除快照。

- 不带 `:checkpoint_id` 选项 → 删除 `session_id` 所有快照
- 带 `:checkpoint_id` 选项 → 仅删该一份
- 不存在也返回 `:ok`（幂等）

# `list`

```elixir
@callback list(session_id :: String.t(), opts :: opts()) ::
  {:ok, [CMDC.Checkpoint.Snapshot.t()]} | {:error, term()}
```

列出会话全部快照（按 `saved_at` 倒序）。

# `load`

```elixir
@callback load(session_id :: String.t(), opts :: opts()) ::
  {:ok, CMDC.Checkpoint.Snapshot.t()} | {:error, :not_found | term()}
```

加载会话最新快照（或指定 `:checkpoint_id`）。

- 默认加载最新（按 `saved_at` 倒序）
- 通过 `Keyword.get(opts, :checkpoint_id)` 加载指定快照
- 会话无快照时返回 `{:error, :not_found}`

# `save`

```elixir
@callback save(
  session_id :: String.t(),
  snapshot :: CMDC.Checkpoint.Snapshot.t(),
  opts :: opts()
) ::
  :ok | {:error, term()}
```

保存一份快照。

实现要保证幂等：用相同 `snapshot.checkpoint_id` 重复调用应该是覆盖写。

---

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