Skip to content

Journaled Entities

Entities have a fixed identity but their information can change over time. The system must record these changes to enable audits, meet compliance requirements, and support forensic analysis. Tracking changes also allows business logic to reference the state of the system at any specific moment in the past.

Journaled Entities are the mechanism that supports these requirements.

Keeping a complete history of entity changes is valuable for:

  • Audits: Reviewing the history of changes to ensure compliance with regulations and internal policies.
  • Forensic Analysis: Investigating issues by examining the state of entities at specific points in time and determining how a change occurred.
  • Immutable Values: Once certain business transactions are committed or agreed, the information relating to that transaction must be immutable. This extends not only to the transaction records directly but also to the reference data the system used to process the transaction. A journaled entity provides a general mechanism for business logic to “freeze” the version of an entity at a particular point.
  • Latest Values: Business logic may need to access the latest version of an entity to refresh its state or present up-to-date information.
  • Analytics: External analytics engines, time-series reporting, and predictive models require access to the complete history of entity versions.

The pair of effective and recorded times that define when a change happens in the system:

  • Effective Time: The time when the change becomes effective for business logic and workflows. This is the “real-world” time of the event.
  • Recorded Time: The time when the change is actually recorded by the system. This may differ from effective time when data is entered retrospectively.

The distinction between effective and recorded time enables the system to correctly answer questions like: “What did the system say was true on date X, as recorded up to date Y?” This supports the audit requirement described above.

An immutable snapshot of an entity’s state at a specific TimeCoordinates. A record contains:

  1. A unique identity for the record itself
  2. The TimeCoordinates for when the change was made (both effective and recorded)
  3. The identity of the user who made the change
  4. An optional note about the change (provided by business logic)
  5. The value of the entity (including its identity) after the change
  6. The identity of the previous record in the entity’s lineage (null for the first record)
  7. A flag indicating whether the entity was deleted in this change

Records are immutable. The system does not physically delete records in normal operation; instead, it creates a new record with the retired flag set to true.

An entity’s lineage is the ordered sequence of all records created for that entity instance over time. Together, these records represent the complete history of the entity. The lineage is navigable through the previous link in each record.

Business logic and other entities can access a journaled entity using:

  1. A reference to a specific record (pinned reference): Directly addresses an immutable record by its record identity.

  2. A reference to the entity with no bitemporal coordinates (floating reference, resolved at request time): The system returns the latest version as of the time of the request.

  3. A reference with specified effective and recorded times (floating reference, resolved to specific coordinates): The system returns the latest version of the entity with effective and recorded times no later than the specified values.

The interpretation of “latest” is: the record with the highest effective time, selected from the set of records whose effective time and recorded time are both no greater than the specified values.

A bitemporal entity record contains the following standard fields:

FieldTypeDescription
eIdUUIDUnique identity for the entity instance (immutable, shared by all records in the lineage)
rIdUUIDUnique identity for this specific record (version)
createdByStringIdentity of the user who created the entity (set at entity creation, not mutable)
createdAtTimeCoordinatesTime when the entity was created
authorStringIdentity of the user who created this record (latest change)
asOfTimeCoordinatesTime when this record was created (effective and recorded)
retiredBooleanWhether the entity was deleted in this version
previousUUID?The rId of the previous record. Null for the first record in the lineage.

Excluded from this document: The RIO abstraction (Result IO / Effect type) and implementation-level details about the common-module repository belong in the Current System section.