# `Threadline`
[🔗](https://github.com/szTheory/threadline/blob/v0.9.0/lib/threadline.ex#L1)

Audit platform for Elixir teams using Phoenix, Ecto, and PostgreSQL.

Threadline combines trigger-backed row-change capture, rich action semantics
(actor/intent/context), and operator-grade exploration.

# `actor_history`

Returns a keyset page of `AuditTransaction` records for a given actor, ordered by
`occurred_at` descending, then `id` descending.

## Options

- `:repo` — required `Ecto.Repo` module
- `:limit` — integer, maximum number of records to return (default 50)
- `:after` — cursor to fetch older records
- `:before` — cursor to fetch newer records
- `:from` — inclusive lower bound on `occurred_at`
- `:to` — inclusive upper bound on `occurred_at`

# `actor_window`

Returns change rows across tables for one actor.

# `actor_window_page`

Returns one keyset page of change rows across tables for one actor.

# `as_of`

Returns the row snapshot for a schema record at a point in time.

## Options

- `:repo` — required `Ecto.Repo` module

# `audit_changes_for_transaction`

Returns every `%Threadline.Capture.AuditChange{}` for a single `audit_transactions.id`.

Delegates to `Threadline.Query.audit_changes_for_transaction/2`. Pass **`repo:`**
(required). Optional **`preload:`** (e.g. `[:transaction]`) is forwarded when
non-empty — see the Query function for ordering and UUID rules.

# `change_diff`

Projects a single `%Threadline.Capture.AuditChange{}` into deterministic, JSON-friendly maps.

Delegates to `Threadline.ChangeDiff.from_audit_change/2`. See that module for `:format`
(including `:export_compat`) and `:expand_insert_fields`.

# `correlation_bundle`

Returns change rows linked to one `correlation_id` with strict correlation semantics.

# `correlation_bundle_page`

Returns one keyset page of changes linked to one `correlation_id`.

# `export_csv`

Exports matching audit changes as CSV (same `filters` / `opts` as `Threadline.Query.timeline/2`).

See `Threadline.Export` and `Threadline.Query.timeline/2`.

# `export_json`

Exports matching audit changes as JSON (same `filters` / `opts` as `Threadline.Query.timeline/2`).

Pass `json_format: :ndjson` in `opts` for newline-delimited objects. See `Threadline.Export`
and `Threadline.Query.timeline/2`.

# `history`

Returns `AuditChange` records for a given schema record, ordered by
`captured_at` descending.

Structs include `:changed_from` when present in the row (sparse prior values on
UPDATE under an opt-in per-table capture function; `nil` when disabled or on
INSERT/DELETE rows).

## Options

- `:repo` — required `Ecto.Repo` module

# `incident_bundle`

Returns one transaction-focused incident bundle with linked transaction/action
context and packaged JSON-ready diffs.

Returns `{:ok, bundle}` when the parent `AuditTransaction` exists, even if it
has no captured changes. Returns `{:error, :not_found}` when the transaction
row does not exist.

# `record_action`

Records a semantic audit action.

## Required options

- `:actor` or `:actor_ref` — `%ActorRef{}` identifying who performed the action
- `:repo` — the `Ecto.Repo` module to use for insertion

## Optional options

- `:status` — `:ok` or `:error` (default: `:ok`)
- `:verb` — string or atom (e.g., `"update"`)
- `:category` — string or atom (e.g., `"membership"`)
- `:reason` — atom (e.g., `:insufficient_permissions`)
- `:comment` — free-text string explanation
- `:correlation_id` — cross-boundary correlation ID string
- `:request_id` — request ID string (from `Plug.RequestId` / `x-request-id`)
- `:job_id` — Oban job ID string

## Returns

- `{:ok, %AuditAction{}}` on success
- `{:error, %Ecto.Changeset{}}` if changeset validation fails
- `{:error, :missing_actor}` if no actor was provided
- `{:error, :invalid_actor_ref}` if the actor fails ActorRef validation
- `{:error, :missing_repo}` if `:repo` is not provided

# `row_history`

Returns the investigation slice for one schema row.

This is the discoverable row-history helper for operators who want one row's
changes without assembling table and primary-key predicates manually.

# `row_history_page`

Returns one keyset page of row history for a single schema row.

# `timeline`

Returns `AuditChange` records across tables, filtered by the given options,
ordered by `captured_at` descending, then `id` descending (same total order as
`Threadline.Query.audit_changes_for_transaction/2`; see `Threadline.Query.timeline/2`).

Use `timeline/2` for eager, bounded slices where returning a full list is still
the simple path. Use `timeline_page/2` for larger investigation windows where
stable keyset traversal matters.

## Options

- `:table` — string or atom; filters by `table_name`
- `:actor_ref` — `%ActorRef{}`; filters by actor via a JOIN to `audit_transactions`
- `:from` — `DateTime`; inclusive lower bound on `captured_at`
- `:to` — `DateTime`; inclusive upper bound on `captured_at`
- `:correlation_id` — non-empty binary; only changes whose transaction is linked to an
  `audit_actions` row with that correlation id (strict semantics — see `Threadline.Query`).
- `:repo` — required `Ecto.Repo` module

# `timeline_page`

Returns one explicit keyset page of timeline results without changing `timeline/2`.

Uses the same filter vocabulary as `timeline/2`, but returns a page struct so
large investigation windows can be traversed incrementally while `timeline/2`
stays eager for existing callers. Paging controls live in `opts`:

- `:page_size` — positive integer, defaults to `1000`
- `:cursor` — `%{captured_at: %DateTime{}, id: uuid}` from a prior page's `next_cursor`
- `:repo` — required `Ecto.Repo` module

# `transaction_context`

Returns one transaction-oriented investigation slice with linked transaction
and optional action metadata.

This packages the existing transaction drill-down primitive into a reusable
helper contract without adding diff or incident-bundle rendering.

---

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