A journal is an internal accounting artifact created by the runtime from a business event. Journals are not the main application-facing API; applications publish business events.
Statuses
draft— built but not yet postedvalidated— passed invariant validationposted— immutable, persisted, executed by the ledger backendreversed— fully reversed by a later reversal journalrejected— preserved for audit
Fields
id—integer()— primary keyevent_id—String.t() | nil— the originating business event idexternal_id—String.t() | nilsource_system/source_type/source_id—String.t() | nil— provenanceselected_policy—String.t() | nil— e.g."cash_deposit"selected_template—String.t() | nildescription—String.t() | nilstatus—String.t()— one ofstatuses/0(default"draft")effective_date—Date.t() | nilposted_at—DateTime.t() | nil— set when postedreversed_at—DateTime.t() | nil— set when reversedreversal_of_id—integer() | nil— self-reference for reversalsidempotency_key—String.t() | nil— unique; prevents duplicate postingexplanation—map() | nil— full knowledge-layer explanationmetadata—map()postings—[Posting.t()]— has_many associationinserted_at/updated_at—DateTime.t()
Rules
- posted journals are immutable
- rejected journals are preserved for audit
- reversals create a new journal that exactly negates the original postings
- the idempotency key prevents duplicate posting
Example
%Logistiki.Accounting.Journal{
id: 1,
event_id: "evt_001",
selected_policy: "cash_deposit",
status: "posted",
effective_date: ~D[2026-07-07],
posted_at: ~U[2026-07-07 12:00:00Z],
idempotency_key: "evt:evt_001:policy:cash_deposit"
}
Summary
Types
The Journal struct type — an internal accounting artifact created by the
runtime from a business event.
Functions
True when the journal is posted (and therefore immutable).
True when the journal is a reversal of another journal.
Returns the list of allowed journal statuses as atoms.
Types
@type t() :: %Logistiki.Accounting.Journal{ __meta__: term(), description: String.t() | nil, effective_date: Date.t() | nil, event_id: String.t() | nil, explanation: map() | nil, external_id: String.t() | nil, id: integer() | nil, idempotency_key: String.t() | nil, inserted_at: DateTime.t() | nil, metadata: map() | nil, posted_at: DateTime.t() | nil, postings: [Logistiki.Accounting.Posting.t()] | Ecto.Association.NotLoaded.t(), reversal_of: term(), reversal_of_id: integer() | nil, reversed_at: DateTime.t() | nil, selected_policy: String.t() | nil, selected_template: String.t() | nil, source_id: String.t() | nil, source_system: String.t() | nil, source_type: String.t() | nil, status: String.t() | nil, updated_at: DateTime.t() | nil }
The Journal struct type — an internal accounting artifact created by the
runtime from a business event.
Fields
id—integer() | nil— primary key (e.g.1)event_id—String.t() | nil— originating event id (e.g."evt_001")external_id—String.t() | nil— external referencesource_system—String.t() | nil— e.g."bank_core"source_type—String.t() | nil— e.g."deposit_received"source_id—String.t() | nil— e.g."wire_123"selected_policy—String.t() | nil— e.g."cash_deposit"selected_template—String.t() | nil— e.g."cash_deposit"description—String.t() | nil— e.g."deposit_received via cash_deposit"status—String.t() | nil— e.g."draft","posted","reversed"effective_date—Date.t() | nil— e.g.~D[2026-07-07]posted_at—DateTime.t() | nil— e.g.~U[2026-07-07 12:00:00Z]reversed_at—DateTime.t() | nilreversal_of_id—integer() | nil— self-reference for reversalsidempotency_key—String.t() | nil— unique duplicate-prevention keyexplanation—map() | nil— full pipeline explanationmetadata—map() | nil— extensible metadatapostings—[Posting.t()] | Ecto.Association.NotLoaded.t()— postingsinserted_at—DateTime.t() | nilupdated_at—DateTime.t() | nil
Example
%Logistiki.Accounting.Journal{
id: 1, event_id: "evt_001", selected_policy: "cash_deposit",
status: "posted", effective_date: ~D[2026-07-07]
}
Functions
True when the journal is posted (and therefore immutable).
Arguments
journal—%__MODULE__{}or any term.
Returns
boolean()—trueonly whenstatus == "posted".
Examples
iex> Logistiki.Accounting.Journal.posted?(%Logistiki.Accounting.Journal{status: "posted"})
true
iex> Logistiki.Accounting.Journal.posted?(%Logistiki.Accounting.Journal{status: "draft"})
false
True when the journal is a reversal of another journal.
Arguments
journal—%__MODULE__{}or any term.
Returns
boolean()—truewhenreversal_of_idis not nil.
Examples
iex> Logistiki.Accounting.Journal.reversal?(%Logistiki.Accounting.Journal{reversal_of_id: 5})
true
iex> Logistiki.Accounting.Journal.reversal?(%Logistiki.Accounting.Journal{reversal_of_id: nil})
false
@spec statuses() :: [atom(), ...]
Returns the list of allowed journal statuses as atoms.
Returns
[atom()]—[:draft, :validated, :posted, :reversed, :rejected]
Examples
iex> :posted in Logistiki.Accounting.Journal.statuses()
true