package audit import "context" // Document is the persisted audit log shape stored in Elasticsearch. type Document struct { ActorID string `json:"actor_id"` ActorType string `json:"actor_type"` Action string `json:"action"` TargetType string `json:"target_type"` TargetID string `json:"target_id"` At int64 `json:"at"` IP string `json:"ip,omitempty"` RequestID string `json:"request_id,omitempty"` UserAgent string `json:"user_agent,omitempty"` Success bool `json:"success"` Metadata map[string]string `json:"metadata,omitempty"` } // SearchFilter defines query filters for audit log search. type SearchFilter struct { ActorID string ActorType string Action string TargetType string TargetID string From int64 To int64 Limit int Offset int } // SearchResult holds paginated audit log search results. type SearchResult struct { Items []Document TotalCount int64 } // Store persists and queries audit documents. type Store interface { Save(ctx context.Context, doc Document) error Search(ctx context.Context, filter SearchFilter) (*SearchResult, error) Close() error } // noopStore discards audit documents when Elasticsearch is disabled. type noopStore struct{} func (noopStore) Save(context.Context, Document) error { return nil } func (noopStore) Search(context.Context, SearchFilter) (*SearchResult, error) { return &SearchResult{Items: []Document{}}, nil } func (noopStore) Close() error { return nil } // NoopStore returns a store that performs no persistence. func NoopStore() Store { return noopStore{} } func entryToDocument(entry Entry) Document { return Document{ ActorID: entry.ActorID, ActorType: entry.ActorType, Action: entry.Action, TargetType: entry.TargetType, TargetID: entry.TargetID, At: entry.At, IP: entry.IP, RequestID: entry.RequestID, UserAgent: entry.UserAgent, Success: entry.Success, Metadata: entry.Metadata, } }