Skip to content

szTheory/threadline

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,361 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Threadline

CI Hex.pm HexDocs CI: Runs on GitHub Actions.

Auditing for Phoenix.

Threadline is an open-source audit library for Elixir teams using Phoenix, Ecto, and PostgreSQL. It combines PostgreSQL trigger capture with semantic actions, then exposes the audit trail through Threadline.Plug, Threadline.Audit.transaction/3, Threadline.record_action/2, Threadline.history/3, Threadline.timeline/2, Threadline.timeline_page/2, Threadline.incident_bundle/2, Threadline.export_json/2, and Threadline.as_of/4.

New Phoenix integrations should use Threadline.Audit.transaction/3; see Getting started §6.

Use it when you want the audit layer in your app, not a separate event system or a black box.

Start here

Evidence plane

Threadline can persist evidence about its own governance surfaces such as trigger coverage, redaction posture, retention runs, export delivery, and the support-lane posture around mounted capabilities. That evidence plane stays host-owned on authorization and product scope: Threadline does not become a legal hold system, an immutable-storage guarantee beyond the host runtime/storage contract, a generic compliance pack, a vendor-specific reporting suite, or a Threadline-owned RBAC or tenancy DSL.

For the canonical non-goals list, read guides/how-threadline-works.md. For the named lane contract, including separately authorized /audit/evidence, read guides/upgrade-path.md. For the public verdict vocabulary (claim_assessment, proven, inferred_posture, unsupported), read guides/domain-reference.md.

What you get

  • Capture: trigger-backed row-change history in PostgreSQL with Threadline.Plug.
  • Semantics: Threadline.Audit.transaction/3 as the recommended audited write path (actor, intent, correlation, and request context); Threadline.record_action/2 is the semantic primitive the helper wraps.
  • Exploration: timelines and history with Threadline.timeline/2, Threadline.timeline_page/2, and Threadline.history/3.
  • Operations: exports, snapshots, coverage checks, retention, redaction, and health tooling via Threadline.export_json/2 and Threadline.as_of/4.

Quick Start

  1. Add threadline to your dependencies:

    def deps do
      [
        {:threadline, "~> 0.6"}
      ]
    end
  2. Configure Threadline:

    Threadline Mix tasks resolve the repo from config :threadline, ecto_repos (not host :ecto_repos alone). Add this to config/config.exs:

    config :threadline,
      ecto_repos: [MyApp.Repo],
      storage_schema: "threadline"

    storage_schema defaults to "threadline" and keeps Threadline-owned tables/functions out of public. Set it to "public" explicitly if you want the historical public-schema footprint, or to another PostgreSQL schema such as "audit".

    See Getting started §2 — Configure Threadline for dual-repo rationale.

  3. Install and migrate:

    mix threadline.install
    mix ecto.migrate
  4. Register triggers for your first audited table:

    mix threadline.gen.triggers --tables posts
    mix ecto.migrate

    See getting-started §4 for the first-table walkthrough and production-checklist §1 for the full expected_tables inventory.

  5. Wrap audited writes with Threadline.Audit.transaction/3 — see Getting started with Threadline in a Phoenix SaaS app §6 for the canonical helper snippet (actor GUC + domain writes + optional action linkage in one transaction).

  6. Query the audit trail:

    Threadline.history(MyApp.Post, post.id, repo: MyApp.Repo)
    Threadline.timeline([table: "posts"], repo: MyApp.Repo)
    Threadline.timeline_page([table: "posts"], repo: MyApp.Repo, page_size: 200)
    Threadline.export_json([table: "posts"], repo: MyApp.Repo)
    Threadline.as_of(MyApp.Post, post.id, DateTime.utc_now(), repo: MyApp.Repo)

Use Threadline.timeline/2 for smaller eager slices. When the window is too large to read eagerly, switch to Threadline.timeline_page/2 and continue with next_cursor instead of offset pagination.

See guides/domain-reference.md for the canonical "which public API first?" table, guides/getting-started-saas.md for the canonical first-hour Phoenix walkthrough, and guides/incident-playbook.md for operator recipes.

Operator Surface

Threadline ships an optional, drop-in LiveView operator console — a dark, branded admin surface for investigating the audit trail natively in your app, with no asset build step. It opens on a task launcher (Find / Verify / Prove) and threads into a filterable change timeline, atomic-transaction and row-level diffs, per-actor history, append-only evidence with Proven / Inferred / Unsupported verdicts, a polled coverage dashboard, and read-only redaction-drift and retention viewers — backed by parity Mix tasks (mix threadline.incident, mix threadline.health.coverage, mix threadline.policy.show) for capture-only adopters. Mount is fail-closed by default. Ensure you have the optional Phoenix surface dependencies declared in mix.exs. The Threadline UI currently ships as an optional in-tree dependency. For details on this architecture decision and support guarantees, see the Upgrade Path.

1-Minute Mount

defmodule MyAppWeb.Router do
  use MyAppWeb, :router
  import Threadline.OperatorSurface.Router

  # Must pipe through your own authentication
  scope "/audit", MyAppWeb do
    pipe_through [:browser, :require_authenticated_admin]

    threadline_operator_surface "/",
      actor_fn: &MyApp.Audit.current_actor/1,
      authorize_fn: &MyApp.Audit.authorize_operator/1
  end
end

For the full first-hour mounted walkthrough, read guides/getting-started-saas.md. For the "fail-closed" security default, authorization setup, and screen inventory, read the Operator Surface guide. For the broader host and framework contract across Threadline.Plug, Threadline.Job, Threadline.Integrations.*, and operator-surface auth/export auth, read guides/integration-contracts.md. For the current support claims, stay with guides/upgrade-path.md rather than inferring broader compatibility from the README.

Notes

  • Threadline works with PgBouncer transaction pooling.
  • Redaction drift uses three states: Config matches deployed, Drift detected, and Could not introspect; rerun mix threadline.gen.triggers if the latter two appear.
  • Redaction, retention, export, and continuity live in the guides and HexDocs.
  • Next operator reads after the first install are guides/performance.md and guides/incident-playbook.md.

Documentation

About

Phoenix auditing – trigger-backed row capture with actor, intent, and request context

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages