Annotation Interface Model


Marks an independently identified and stored domain model.

Unlike an Aggregate, a model is its own persistence and lifecycle boundary. Loading or updating it does not require loading a parent, sibling, child, or an artificial aggregate root. A model may still contain embedded entities declared with @Member; those members share the model's stream, cache, search document, snapshots, and lifecycle.

Choose this boundary from domain lifecycle first: state that can be created, changed, retained, deleted, or whose history matters independently is a separate model, even when it is normally displayed in a parent's collection. Connect such a child with @Parent. A meaningful domain identity is strong evidence for that boundary, not an additional gate: an independently living child may use a globally unique ID or a parent-scoped ID. Collection shape, searchability, storage format, update frequency, and convenient embedding do not make independently living state a Member.

Model identity is the repository representation of its @EntityId. Applications can use a typed Id, annotation-level prefix/postfix affixes, or both to isolate otherwise equal functional identifiers.

An @Apply method targets a model by returning that model. Returning null deletes the targeted model while retaining the applied event according to the configured publication settings. Returning void is invalid for model applies because it does not identify a stored result. Legacy mutable aggregate applies remain supported.

Event-sourced and document-based loading

eventSourced() selects the normal load path, not whether applied events are stored or published. An event-sourced model is reconstructed from its model stream, optionally from a snapshot. A document-based model is loaded directly from its current document. In both cases, event storage and publication are controlled independently by eventPublication(), publicationStrategy(), and per-apply overrides. Choose this persistence strategy after choosing the lifecycle boundary. Splitting independently living children into their own models often makes their individual streams small enough for straightforward event sourcing even when the former shared root had a very large event history.

Example

@Model(searchable = true)
public record Product(@EntityId ProductId productId, String name) {
    @Apply
    Product rename(RenameProduct command) {
        return new Product(productId, command.name());
    }
}
An update may instead create or update the model from a payload-side @Apply. When both sides define an applicable apply, Fluxzero applies the payload first and invokes the model method against that intermediate state. This lets one instance method consistently enforce model-owned behavior for both creation and later updates.
See Also:
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    Controls whether applies producing this model may be exposed as automatic command handlers.
    boolean
    Whether the latest model state should be stored in the shared application cache.
    int
    Number of older model versions retained in the shared cache.
    int
    Frequency at which intermediate states are checkpointed within one reconstruction session.
    Controls when model changes are committed and whether completion-phase commits may run concurrently.
    io.fluxzero.common.api.modeling.ModelConflictPolicy
    Conflict handling for this model when an apply does not provide an explicit override.
    Controls whether an applied update produces an event when the returned model is unchanged.
    boolean
    Whether normal loads reconstruct the model from its event stream.
    Advanced configuration for the materialized whole-graph search document.
    boolean
    Whether unknown events should be ignored while reconstructing an event-sourced model.
    boolean
    Whether Fluxzero should asynchronously materialize the complete model graph as a separate search document.
    int
    Maximum number of snapshots retained for this model.
    Controls whether applied events are stored, published, or both.
    boolean
    Whether the model should expose a synchronous current document through its ordinary class-based search collection.
    Advanced configuration for the model's direct search document.
    int
    Number of stored model events between snapshots.
  • Element Details

    • conflictPolicy

      io.fluxzero.common.api.modeling.ModelConflictPolicy conflictPolicy
      Conflict handling for this model when an apply does not provide an explicit override.
      Default:
      DEFAULT
    • automaticHandling

      AutomaticModelHandling automaticHandling
      Controls whether applies producing this model may be exposed as automatic command handlers.
      Default:
      DEFAULT
    • eventSourced

      boolean eventSourced
      Whether normal loads reconstruct the model from its event stream.

      When disabled, the current model is loaded directly from its document through the configured DocumentSerializer. This setting does not suppress storing or publishing events produced by Apply methods. A state-changing event-sourced model apply must store its reconstructing event; a PUBLISH_ONLY or NEVER transition that would change state is rejected before commit. A publish-only no-op remains a valid domain notification when publication is explicitly set to ALWAYS.

      Default:
      true
    • ignoreUnknownEvents

      boolean ignoreUnknownEvents
      Whether unknown events should be ignored while reconstructing an event-sourced model.
      Default:
      false
    • snapshotPeriod

      int snapshotPeriod
      Number of stored model events between snapshots. 0 disables periodic snapshots.
      Default:
      0
    • maxSnapshotCount

      int maxSnapshotCount
      Maximum number of snapshots retained for this model. Values below 1 are treated as 1.
      Default:
      1
    • cached

      boolean cached
      Whether the latest model state should be stored in the shared application cache.

      Models participating in an commit may additionally be retained in an commit-local cache until the commit completes.

      Default:
      true
    • cachingDepth

      int cachingDepth
      Number of older model versions retained in the shared cache. -1 retains all available cached versions; 0 retains only the latest version.

      Independent models retain one previous version by default so event handlers can compare the event-visible model with Entity.previous(). Retaining an unbounded revision chain must be an explicit choice because model caches are expected to contain far more keys than aggregate caches.

      Default:
      1
    • checkpointPeriod

      int checkpointPeriod
      Frequency at which intermediate states are checkpointed within one reconstruction session.

      Checkpoints avoid replaying the same prefix for repeated historical dependency loads. They are bounded by the reconstruction session and are not retained as document revisions.

      Default:
      100
    • commitPolicy

      ModelCommitPolicy commitPolicy
      Controls when model changes are committed and whether completion-phase commits may run concurrently.

      The default value resolves from fluxzero.model.commitPolicy when present and otherwise uses ModelCommitPolicy.ASYNC_AFTER_HANDLER_AWAIT_AFTER_BATCH. Independent models were introduced with this default, so it does not depend on the active defaults version.

      Default:
      DEFAULT
    • eventPublication

      EventPublication eventPublication
      Controls whether an applied update produces an event when the returned model is unchanged.

      Independent models default to IF_MODIFIED, so a no-op apply does not create a model-stream or globally published event. Use ALWAYS when an unchanged apply intentionally represents a domain event. This setting is evaluated before publicationStrategy().

      Default:
      IF_MODIFIED
    • publicationStrategy

      EventPublicationStrategy publicationStrategy
      Controls whether applied events are stored, published, or both.

      PUBLISH_ONLY may mutate a document-loaded model. For an event-sourced model it may only publish an unchanged result, because otherwise the next reconstruction could not reproduce the committed state.

      Default:
      DEFAULT
    • searchable

      boolean searchable
      Whether the model should expose a synchronous current document through its ordinary class-based search collection.

      Successful commit completion makes the directly changed model searchable in its own collection. This setting does not control graph participation: a model connected through an explicit Parent.pathInParent() still supplies an internal current document for virtual and materialized graph composition. Private component documents are isolated per model type and can be selected through relationship constraints such as Search.whereDescendant(Object, io.fluxzero.common.api.search.Constraint...), without exposing the model through its ordinary class-based search collection. Composed root documents are separate projections.

      Default:
      false
    • searchProjection

      Searchable searchProjection
      Advanced configuration for the model's direct search document.

      This configuration does not enable indexing by itself; set searchable() to true. Defaults to the model's simple class name as collection and to event timestamps when no timestamp paths are configured.

      Default:
      @io.fluxzero.sdk.persisting.search.Searchable
    • materializeGraph

      boolean materializeGraph
      Whether Fluxzero should asynchronously materialize the complete model graph as a separate search document.

      Fluxzero retains the root's current document in its direct collection when searchable() is enabled and otherwise in the same type-isolated private component storage used by non-searchable children. Only the separately named graph collection is allowed to lag; its high-watermark is exposed through the model repository. The collection defaults to the resolved direct-model collection plus -graphs when searchable, or to <simple model name>-graphs otherwise.

      Default:
      false
    • graphProjection

      GraphProjection graphProjection
      Advanced configuration for the materialized whole-graph search document.

      This configuration does not enable materialization by itself; set materializeGraph() to true.

      Default:
      @io.fluxzero.sdk.modeling.GraphProjection