Threadline.Retention.Policy (Threadline v1.0.0)

Copy Markdown View Source

Validates config :threadline, :retention before purge runs.

Threadline supports a single global retention window (:keep_days or :max_age_seconds, mutually exclusive) plus an enabled flag that must be true for destructive purge. delete_empty_transactions defaults to true (remove parent audit_transactions rows with no remaining children after change deletes).

Per-table and per-tenant overrides are not supported; this module validates the global policy shape only.

validate_config!/1 checks configuration, resolve!/1 returns normalized policy values, and cutoff_utc_datetime_usec!/1 computes the expiry cutoff.

Summary

Types

The keyword-list or map form accepted by retention policy validation and resolution.

A retention config map. Recognized keys are atom or string spellings of :enabled, :delete_empty_transactions, :keep_days, and :max_age_seconds. The boolean keys accept booleans or the strings "true" and "false"; window values accept positive integers. Other keys are ignored, and the string-key map arm represents extra keys and mixed atom/string maps.

An atom-keyed option in the retention policy configuration.

An option accepted by cutoff_utc_datetime_usec!/1.

t()

Normalized retention options as returned by resolve/1.

Functions

Returns UTC DateTime strictly before which AuditChange.captured_at values are considered expired for purge (i.e. delete rows with captured_at < cutoff).

Resolves config into a struct or raises like validate_config!/1.

Returns :ok when retention config from Application.get_env(:threadline, :retention) is valid.

Types

config()

@type config() :: [config_opt()] | config_map()

The keyword-list or map form accepted by retention policy validation and resolution.

config_map()

@type config_map() ::
  %{
    optional(:enabled) => boolean() | String.t(),
    optional(:delete_empty_transactions) => boolean() | String.t(),
    optional(:keep_days) => pos_integer() | nil | false,
    optional(:max_age_seconds) => pos_integer() | nil | false
  }
  | %{optional(String.t()) => term()}

A retention config map. Recognized keys are atom or string spellings of :enabled, :delete_empty_transactions, :keep_days, and :max_age_seconds. The boolean keys accept booleans or the strings "true" and "false"; window values accept positive integers. Other keys are ignored, and the string-key map arm represents extra keys and mixed atom/string maps.

For boolean keys, a present atom key wins over its string spelling even when its value is invalid. For window keys, atom_value || string_value is used, so atom nil or false falls back to the matching string key while 0 or another truthy invalid atom value keeps its validation error. Positive window values remain mutually exclusive; when both are absent, the test environment uses a one-day default.

config_opt()

@type config_opt() ::
  {:enabled, boolean() | String.t()}
  | {:delete_empty_transactions, boolean() | String.t()}
  | {:keep_days, pos_integer() | nil | false}
  | {:max_age_seconds, pos_integer() | nil | false}

An atom-keyed option in the retention policy configuration.

cutoff_opt()

@type cutoff_opt() :: {:policy, t()}

An option accepted by cutoff_utc_datetime_usec!/1.

t()

@type t() :: %Threadline.Retention.Policy{
  delete_empty_transactions: boolean(),
  enabled: boolean(),
  window_seconds: pos_integer()
}

Normalized retention options as returned by resolve/1.

Functions

cutoff_utc_datetime_usec!(opts \\ [])

@spec cutoff_utc_datetime_usec!([cutoff_opt()]) :: DateTime.t()

Returns UTC DateTime strictly before which AuditChange.captured_at values are considered expired for purge (i.e. delete rows with captured_at < cutoff).

Uses DateTime.add/3 in microsecond mode for consistency with :utc_datetime_usec.

Options

  • :policy — normalized retention policy. Optional. Defaults to the configured policy.

Returns

  • The UTC cutoff timestamp.

Other option keys are ignored.

resolve!(opts)

@spec resolve!(config()) :: t()

Resolves config into a struct or raises like validate_config!/1.

validate_config!(opts)

@spec validate_config!(config()) :: :ok

Returns :ok when retention config from Application.get_env(:threadline, :retention) is valid.

Raises ArgumentError with a message containing "retention" when either boolean option is not a boolean or its string spelling, when both window keys are set, or when a window is non-positive or missing outside the test environment.

In :test, missing :keep_days / :max_age_seconds is allowed only when the caller passes a non-empty map/list that still fails other checks — for empty config in test, hosts should set explicit values in config/test.exs.