Documentation
¶
Overview ¶
Package audit records model history and typed domain events through the actual business transaction. Registration is explicit and never migrates storage.
Index ¶
- Constants
- func CorrelationFromContext(ctx context.Context) value.Optional[Correlation]
- func FindModel[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, ...) (value.Optional[ModelRecord[M, K]], error)
- func Migrations() []migrate.Definition
- func ModelHistory[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, ...) (orm.PageResult[ModelRecord[M, K]], error)
- func Register(r *foundation.Registrar, pool foundation.Key[*database.DB], ...) error
- func WithArea(ctx context.Context, area Area) (context.Context, error)
- func WithCorrelation(ctx context.Context, correlation Correlation) (context.Context, error)
- type Action
- func (a Action[P]) Find(ctx context.Context, executor database.Executor, recorder *Recorder, ...) (value.Optional[ActionRecord[P]], error)
- func (a Action[P]) Name() ActionName
- func (a Action[P]) Record(ctx context.Context, tx *database.Tx, recorder *Recorder, payload P) (ActionID[P], error)
- func (a Action[P]) Timeline(ctx context.Context, executor database.Executor, recorder *Recorder, ...) (Timeline[ActionRecord[P]], error)
- func (a Action[P]) Validate() error
- func (a Action[P]) Version() Version
- type ActionEntry
- type ActionID
- type ActionName
- type ActionRecord
- type Activity
- type Area
- type Config
- type Correlation
- type Metadata
- type ModelEntry
- type ModelID
- type ModelRecord
- type Recorder
- func (r *Recorder) CountBefore(ctx context.Context, tx *database.Tx, cutoff temporal.DateTime) (int64, error)
- func (*Recorder) Format(state fmt.State, _ rune)
- func (r *Recorder) PruneBefore(ctx context.Context, tx *database.Tx, cutoff temporal.DateTime, limit int) (int64, error)
- func (r *Recorder) PruneRetention(ctx context.Context, tx *database.Tx, now temporal.DateTime, limit int) (int64, error)
- func (r *Recorder) RecordModel(ctx context.Context, tx *database.Tx, entry record.Entry) error
- func (r *Recorder) RetentionCutoff(now temporal.DateTime) (temporal.DateTime, error)
- type Scope
- func (s *Scope) CountBefore(ctx context.Context, cutoff temporal.DateTime) (int64, error)
- func (*Scope) Format(state fmt.State, _ rune)
- func (*Scope) LogValue() slog.Value
- func (s *Scope) PruneBefore(ctx context.Context, cutoff temporal.DateTime, batch int) (int64, error)
- func (s *Scope) PruneRetention(ctx context.Context, now temporal.DateTime, batch int) (int64, error)
- func (s *Scope) RetentionCutoff(now temporal.DateTime) (temporal.DateTime, error)
- func (s *Scope) Within(ctx context.Context, tx *database.Tx, fn func(*database.Tx, *Recorder) error) error
- type Sequence
- type Timeline
- func ActionTimelineFor[M, K, P any](ctx context.Context, executor database.Executor, recorder *Recorder, ...) (Timeline[ActionRecord[P]], error)
- func ActorActivity[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, ...) (Timeline[Activity], error)
- func CorrelationActivity(ctx context.Context, executor database.Executor, recorder *Recorder, ...) (Timeline[Activity], error)
- func ModelTimeline[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, ...) (Timeline[ModelRecord[M, K]], error)
- func SubjectActivity[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, ...) (Timeline[Activity], error)
- func SystemActivity(ctx context.Context, executor database.Executor, recorder *Recorder, ...) (Timeline[Activity], error)
- type TimelineRequest
- type Version
Constants ¶
const ( DefaultMaxValueBytes = 64 << 10 ValueBytesFloor = 256 ValueBytesCeiling = record.MaxCapturedValueBytes )
DefaultMaxValueBytes is the per-value threshold used when Config leaves MaxValueBytes zero. ValueBytesFloor and ValueBytesCeiling bound explicit settings.
Variables ¶
This section is empty.
Functions ¶
func CorrelationFromContext ¶
func CorrelationFromContext(ctx context.Context) value.Optional[Correlation]
CorrelationFromContext returns the correlation audit writes in ctx will store.
func FindModel ¶
func FindModel[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, template model.Reference[M, K], id ModelID[M]) (value.Optional[ModelRecord[M, K]], error)
FindModel reads an audit-row ID owned by the expected model. Supply a generated zero model's FoundryReference as the decoding template; its current key is not used. Foreign models/areas are absent, and no subject-model lookup occurs.
func Migrations ¶
func Migrations() []migrate.Definition
Migrations returns owned historical definitions. Register and run them with the ordinary explicit migration command against the recorder's database/schema. Missing storage fails enabled audit writes instead of silently discarding them.
AddHistoryKeys rewrites the table once: it assigns every existing row an insertion sequence in (created_at, id) order, records the original redaction policy, backfills request correlation and adds database-generated subject and actor lookup keys with their history indexes. The lookup keys hash UTF-8 text, so the migration requires a UTF8 (or SQL_ASCII) database encoding.
func ModelHistory ¶
func ModelHistory[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, subject model.Reference[M, K], request orm.PageRequest) (orm.PageResult[ModelRecord[M, K]], error)
ModelHistory reads one stored subject's lifecycle history in the selected area, newest first by insertion sequence. It does not fetch the subject model or require that it still exists. Page count and rows share ORM pagination's transaction/isolation contract; use ModelTimeline for keyset pages.
func Register ¶
func Register(r *foundation.Registrar, pool foundation.Key[*database.DB], key foundation.Key[*Recorder], config Config, models ...record.Declaration) error
Register constructs one recorder and adds generated model audit observers to the selected pool. Foundation owns duplicate detection, dependency resolution and freezing; model callbacks retain the constructed recorder directly.
func WithArea ¶
WithArea scopes subsequent audit writes/reads while retaining cancellation and attribution. It does not authenticate the caller or grant history access.
func WithCorrelation ¶
WithCorrelation scopes subsequent audit writes to an explicit correlation, such as one batch of a bulk operation. Without it, rows use the attribution request ID when one is present, so a request's changes can be read together.
Types ¶
type Action ¶
type Action[P any] struct { // contains filtered or unexported fields }
Action declares a versioned domain audit DTO. Declare and reuse one descriptor for each schema. Redaction never changes the input or silently hydrates a partially redacted DTO on subsequent reads.
func Define ¶
func Define[P any](name ActionName, version Version) Action[P]
Define returns an action descriptor for the payload type, name and version. Validation is deferred to Validate or use of the descriptor.
func (Action[P]) Find ¶
func (a Action[P]) Find(ctx context.Context, executor database.Executor, recorder *Recorder, id ActionID[P]) (value.Optional[ActionRecord[P]], error)
Find selects only this action schema and area. It validates persisted DTO and redaction metadata again under the row's own redaction policy; a foreign action/version/area is absent.
func (Action[P]) Record ¶
func (a Action[P]) Record(ctx context.Context, tx *database.Tx, recorder *Recorder, payload P) (ActionID[P], error)
Record captures a domain event without a model subject. It neither commits the outer transaction nor delivers a notification. Its ID is not a receipt.
func (Action[P]) Timeline ¶
func (a Action[P]) Timeline(ctx context.Context, executor database.Executor, recorder *Recorder, request TimelineRequest) (Timeline[ActionRecord[P]], error)
Timeline lists this action name/version in the selected area, newest first.
type ActionEntry ¶
type ActionEntry[P any] struct { // contains filtered or unexported fields }
ActionEntry distinguishes audit-row IDs by their action payload type.
type ActionID ¶
type ActionID[P any] = model.ID[ActionEntry[P]]
ActionID identifies an audit row for payload type P.
func ActionActivityID ¶
ActionActivityID converts a domain activity into its typed ID when the row was recorded by this action name and version.
func ParseActionID ¶
ParseActionID parses the textual audit-row identifier for payload type P.
func RecordFor ¶
func RecordFor[M, K, P any](ctx context.Context, tx *database.Tx, recorder *Recorder, action Action[P], subject model.Reference[M, K], payload P) (ActionID[P], error)
RecordFor captures a concrete model-owned subject reference without another model lookup or read accessor. Origin/subject metadata is not authorization.
type ActionRecord ¶
ActionRecord is immutable persisted domain history. Document.Decode returns a fresh DTO only when the stored representation is complete and unredacted. Its embedded Metadata supplies Sequence, Area, Origin, Correlation, Route and CreatedAt.
func (ActionRecord[P]) Document ¶
func (r ActionRecord[P]) Document() record.Document[P]
Document returns the captured audit representation of the payload.
func (ActionRecord[P]) Format ¶
func (ActionRecord[P]) Format(state fmt.State, _ rune)
Format writes a fixed label without exposing the record's contents.
func (ActionRecord[P]) ID ¶
func (r ActionRecord[P]) ID() ActionID[P]
ID returns the typed audit-row identifier.
type Activity ¶
type Activity struct {
Metadata
// contains filtered or unexported fields
}
Activity is a payload-free summary of one stored audit row for heterogeneous timelines: a subject's combined history, an actor's changes or everything written under one correlation. Load typed details with FindModel/Action.Find using ModelActivityID or ActionActivityID. Its embedded Metadata supplies Sequence, Area, Origin, Correlation, Route and CreatedAt.
func (Activity) Action ¶
func (a Activity) Action() (ActionName, Version)
Action returns the domain action name and version; both are zero for model rows.
func (Activity) IsAction ¶
IsAction reports whether the lifecycle operation is zero, as it is for domain actions.
type Area ¶
type Area string
Area identifies an application audit namespace. It is attribution metadata, not an authorization boundary; applications authorize access to history.
type Config ¶
Config is immutable after recorder construction. Zero RetentionDays disables configured pruning. Nothing runs retention automatically. A captured value larger than MaxValueBytes (zero selects DefaultMaxValueBytes) is stored as a size and SHA-256 digest marker instead of failing the business write.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the application area and default per-value byte limit.
type Correlation ¶
type Correlation string
Correlation groups audit rows written by one logical operation, such as a request, import or bulk change. It is metadata for reading history together, not a secret, authorization scope or idempotency key.
func NewCorrelation ¶
func NewCorrelation() (Correlation, error)
NewCorrelation generates a time-ordered UUIDv7 correlation identifier.
func (Correlation) Validate ¶
func (c Correlation) Validate() error
Validate applies the attribution request-ID bounds: 1–128 bytes of valid, trimmed UTF-8 without control characters.
type Metadata ¶ added in v0.3.0
type Metadata struct {
// contains filtered or unexported fields
}
Metadata contains the provenance shared by ModelRecord, ActionRecord and Activity. Audit history readers populate it from validated stored rows. These records embed Metadata to promote Sequence, Area, Origin, Correlation, Route and CreatedAt. Its zero value describes no stored row: accessors return zero values and absent optional values.
func (Metadata) Area ¶ added in v0.3.0
Area returns the audit namespace in which the row was recorded.
func (Metadata) Correlation ¶ added in v0.3.0
func (m Metadata) Correlation() value.Optional[Correlation]
Correlation returns the logical operation identifier captured for the row, if set.
func (Metadata) CreatedAt ¶ added in v0.3.0
CreatedAt returns the timestamp captured when the row was written.
func (Metadata) Origin ¶ added in v0.3.0
func (m Metadata) Origin() attribution.Origin
Origin returns the attribution captured when the row was written.
type ModelEntry ¶
type ModelEntry[M any] struct { // contains filtered or unexported fields }
ModelEntry owns an audit-row ID for one model; it is not a stored model row.
type ModelID ¶
type ModelID[M any] = model.ID[ModelEntry[M]]
ModelID identifies an audit row for model M.
type ModelRecord ¶
ModelRecord contains complete audit representations, not a partial model. Its embedded Metadata supplies Sequence, Area, Origin, Correlation, Route and CreatedAt.
func (ModelRecord[M, K]) Changes ¶
func (r ModelRecord[M, K]) Changes() record.Model[M, K]
Changes returns the captured model audit representation.
func (ModelRecord[M, K]) Format ¶
func (ModelRecord[M, K]) Format(state fmt.State, _ rune)
Format writes a fixed label without exposing captured changes.
func (ModelRecord[M, K]) ID ¶
func (r ModelRecord[M, K]) ID() ModelID[M]
ID returns the typed audit-row identifier.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder has no independent resource lifetime or database pool. Its methods use caller-owned executors/transactions and are safe for concurrent operations.
func (*Recorder) CountBefore ¶
func (r *Recorder) CountBefore(ctx context.Context, tx *database.Tx, cutoff temporal.DateTime) (int64, error)
CountBefore counts the entries of the selected area created before cutoff, the rows PruneBefore would remove, without reading their payloads.
func (*Recorder) PruneBefore ¶
func (r *Recorder) PruneBefore(ctx context.Context, tx *database.Tx, cutoff temporal.DateTime, limit int) (int64, error)
PruneBefore removes at most limit old entries in the selected area through the supplied transaction. Call explicitly from an authorized maintenance operation. It does not reset tables, hydrate payloads, dispatch observers or loop forever.
func (*Recorder) PruneRetention ¶
func (r *Recorder) PruneRetention(ctx context.Context, tx *database.Tx, now temporal.DateTime, limit int) (int64, error)
PruneRetention derives the explicit cutoff from supplied UTC time. Each day is 24 hours. Zero configured retention disables this helper; no background work or default deletion schedule is installed by constructing/registering a recorder.
func (*Recorder) RecordModel ¶
RecordModel implements the generated observer boundary. Captured stored changes are validated before any SQL. Values above the configured MaxValueBytes are stored as digest markers; a large payload never fails the write. Other failures roll back the model write.
type Scope ¶
type Scope struct {
// contains filtered or unexported fields
}
Scope is a concrete, immutable dependency for domain constructors. It borrows one recorder and database; callers may retain it until application shutdown. It does not retain a service resolver or acquire another pool.
func NewScope ¶
NewScope validates and binds a borrowed database and recorder to the audit schema. It acquires no resources and performs no database I/O.
func (*Scope) CountBefore ¶
CountBefore counts, in one read-only transaction, the entries PruneBefore would remove from the selected area. It never reads payloads or deletes.
func (*Scope) PruneBefore ¶
func (s *Scope) PruneBefore(ctx context.Context, cutoff temporal.DateTime, batch int) (int64, error)
PruneBefore repeatedly removes bounded batches of entries older than cutoff from the selected area, each batch in its own transaction, until a batch removes fewer than batch rows or ctx ends. It returns the rows removed by committed batches, including when a later batch fails; rerunning is safe. Call it only from an explicit, authorized maintenance operation.
func (*Scope) PruneRetention ¶
func (s *Scope) PruneRetention(ctx context.Context, now temporal.DateTime, batch int) (int64, error)
PruneRetention derives one cutoff from now and the configured retention, then prunes in bounded batches like PruneBefore. Zero retention returns Missing.
func (*Scope) RetentionCutoff ¶
RetentionCutoff derives the configured retention cutoff for now, like Recorder.RetentionCutoff.
func (*Scope) Within ¶
func (s *Scope) Within(ctx context.Context, tx *database.Tx, fn func(*database.Tx, *Recorder) error) error
Within joins the caller's business transaction through a savepoint. All audit work must use child; the configured schema is restored afterward. Success does not commit the caller's transaction, and another database's transaction fails.
type Sequence ¶
type Sequence int64
Sequence is the database-assigned insertion order of audit rows. It orders history correctly even when several rows share one transaction timestamp. It is a position for keyset reads, not an identifier or a count.
type Timeline ¶
Timeline is one keyset page. Next is set when older rows may follow; it is a position hint, not a snapshot across concurrent writes.
func ActionTimelineFor ¶
func ActionTimelineFor[M, K, P any](ctx context.Context, executor database.Executor, recorder *Recorder, action Action[P], subject model.Reference[M, K], request TimelineRequest) (Timeline[ActionRecord[P]], error)
ActionTimelineFor lists this action's records about one subject, newest first, using the indexed subject key and an exact identity comparison.
func ActorActivity ¶
func ActorActivity[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, actor model.Reference[M, K], request TimelineRequest) (Timeline[Activity], error)
ActorActivity lists rows whose attribution names this model actor, newest first. The actor key is indexed; each row's origin is also compared exactly.
func CorrelationActivity ¶
func CorrelationActivity(ctx context.Context, executor database.Executor, recorder *Recorder, correlation Correlation, request TimelineRequest) (Timeline[Activity], error)
CorrelationActivity lists every row written under one correlation, such as one request or explicit batch, newest first.
func ModelTimeline ¶
func ModelTimeline[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, subject model.Reference[M, K], request TimelineRequest) (Timeline[ModelRecord[M, K]], error)
ModelTimeline reads one subject's lifecycle history newest first using the indexed insertion sequence. It performs one bounded query without a count; pass Next as Before to continue. Concurrent writes do not form a snapshot.
func SubjectActivity ¶
func SubjectActivity[M, K any](ctx context.Context, executor database.Executor, recorder *Recorder, subject model.Reference[M, K], request TimelineRequest) (Timeline[Activity], error)
SubjectActivity lists model changes and domain actions recorded for one subject, newest first, without decoding their payloads.
func SystemActivity ¶
func SystemActivity(ctx context.Context, executor database.Executor, recorder *Recorder, system attribution.SystemID, request TimelineRequest) (Timeline[Activity], error)
SystemActivity lists rows attributed to one system identity, newest first.
type TimelineRequest ¶
TimelineRequest selects at most Size rows, newest first, strictly older than Before when it is set. Pass a returned Timeline.Next as Before to continue.
func (TimelineRequest) Validate ¶
func (r TimelineRequest) Validate() error
Validate checks the page size and optional positive sequence, returning fault.Invalid on failure.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package command supplies the explicit audit retention operation.
|
Package command supplies the explicit audit retention operation. |
|
Package record supplies typed audit snapshots and generated registration contracts below audit storage.
|
Package record supplies typed audit snapshots and generated registration contracts below audit storage. |