audit

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 12 Imported by: 0

README

togo

togo-framework/audit

marketplace pkg.go.dev MIT

Activity log + model versioning for togo — who changed what, with diffs and restore.

Install

togo install togo-framework/audit

audit is the togo answer to Spatie Activitylog / PaperTrail / django-reversion. It records an activity log of changes to your models — the action, the subject, the actor (causer), a field-level diff, and request IP/User-Agent — plus optional model versioning with restore.

Features

  • Activity logLog / LogChange write append-only entries to activity_log, indexed by subject, causer and action.
  • Automatic diffsLogChange(old, new) stores only the fields that changed, as {old, new}.
  • Actor capture — the bundled Middleware pulls the causer (X-User-Id), client IP and User-Agent from the request into context, so logs are attributed automatically.
  • Model versioningSnapshot stores point-in-time JSON snapshots; Restore returns prior state to re-apply.
  • Queryable — filter by subject / causer / action / time, with pagination, over a Go API and REST.

Usage

import "github.com/togo-framework/audit"

a, _ := audit.FromKernel(k)

// Log an action with an explicit changeset:
a.Log(ctx, "created", "post", post.ID, userID, map[string]any{"title": post.Title})

// Or auto-diff old → new (stores only changed fields):
a.LogChange(ctx, "updated", "post", post.ID, userID, oldMap, newMap)

// Versioning + restore:
a.Snapshot(ctx, "post", post.ID, oldMap, userID) // snapshot before a change
data, ver, _ := a.Restore(ctx, versionID)         // get prior state to re-apply

// Query the trail:
a.Activity(ctx, audit.Filter{SubjectType: "post", SubjectID: post.ID})
a.Activity(ctx, audit.Filter{CauserID: userID, Action: "deleted", Limit: 50})

Causer / IP / User-Agent are filled from the request context automatically (the plugin mounts audit.Middleware on the kernel router).

REST API

Method Path Purpose
GET /api/audit/activity filtered activity (subject_type, subject_id, causer_id, action, limit, offset)
GET /api/audit/subjects/{type}/{id} a record's full history
GET /api/audit/versions/{type}/{id} snapshots for a subject
POST /api/audit/versions/{id}/restore snapshot data to re-apply
GET /api/audit/dashboard recent activity feed

Configuration

No required env. Audit creates its tables (activity_log, versions) on boot via the kernel database (works on SQLite/Postgres/MySQL through togo's ORM). High-volume deployments can partition activity_log by created_at.


Premium sponsors

ID8 Media  ·  One Studio

Support togo — become a sponsor.

Documentation

Overview

Package audit records an activity log of changes to your models/resources — who did what to which subject, with a field-level diff — plus optional model versioning with restore. It is the togo answer to Spatie Activitylog / PaperTrail / django-reversion.

a, _ := audit.FromKernel(k)
a.LogChange(ctx, "updated", "post", post.ID, userID, oldPost, newPost) // diffs old→new
a.Snapshot(ctx, "post", post.ID, oldPost, userID)                      // version for restore

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Diff

func Diff(old, new map[string]any) map[string]any

Diff returns a changeset of fields that differ between old and new (added/removed/changed), each as {old,new}.

func Middleware

func Middleware(next http.Handler) http.Handler

Middleware captures the causer (X-User-Id header), client IP and user-agent into the request context so subsequent audit.Log calls auto-fill them.

func WithMeta

func WithMeta(ctx context.Context, m Meta) context.Context

WithMeta attaches actor/request metadata to a context so Log can pick it up.

Types

type Change

type Change struct {
	Old any `json:"old"`
	New any `json:"new"`
}

Change is a single field's before/after.

type Entry

type Entry struct {
	ID          string   `db:"id" json:"id"`
	Action      string   `db:"action" json:"action"`
	SubjectType string   `db:"subject_type" json:"subject_type"`
	SubjectID   string   `db:"subject_id" json:"subject_id"`
	CauserID    string   `db:"causer_id" json:"causer_id"`
	Changes     JSONText `db:"changes" json:"changes"`
	IP          string   `db:"ip" json:"ip,omitempty"`
	UserAgent   string   `db:"user_agent" json:"user_agent,omitempty"`
	CreatedAt   string   `db:"created_at" json:"created_at"`
}

Entry is one activity-log record.

type Filter

type Filter struct {
	SubjectType string
	SubjectID   string
	CauserID    string
	Action      string
	Limit       int
	Offset      int
}

Filter narrows an activity query.

type JSONText

type JSONText []byte

JSONText is a JSON value stored in a text column. It scans from string/[]byte and marshals back to raw JSON (so API responses nest objects, not strings).

func (JSONText) Map

func (j JSONText) Map() map[string]any

Map decodes the JSON into a map (nil on error).

func (JSONText) MarshalJSON

func (j JSONText) MarshalJSON() ([]byte, error)

MarshalJSON emits the raw JSON.

func (*JSONText) Scan

func (j *JSONText) Scan(src any) error

Scan implements sql.Scanner.

type Meta

type Meta struct {
	CauserID  string
	IP        string
	UserAgent string
}

Meta carries the actor + request info captured for an entry.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is the audit runtime stored on the kernel (k.Get("audit")).

func FromKernel

func FromKernel(k *togo.Kernel) (*Service, bool)

FromKernel returns the audit Service registered on the kernel.

func (*Service) Activity

func (s *Service) Activity(ctx context.Context, f Filter) ([]Entry, error)

Activity returns activity-log entries matching the filter, newest first.

func (*Service) Log

func (s *Service) Log(ctx context.Context, action, subjectType, subjectID, causerID string, changes map[string]any) (*Entry, error)

Log writes an activity-log entry. changes is an arbitrary changeset (often the output of Diff). IP / user-agent / causer are filled from the request context (see Middleware) when not supplied.

func (*Service) LogChange

func (s *Service) LogChange(ctx context.Context, action, subjectType, subjectID, causerID string, old, new map[string]any) (*Entry, error)

LogChange diffs old→new and records the changeset as an "updated"-style entry.

func (*Service) Restore

func (s *Service) Restore(ctx context.Context, versionID string) (map[string]any, *Version, error)

Restore returns the snapshot data for a version id. The caller applies it to the live record (audit owns history, not your tables).

func (*Service) Snapshot

func (s *Service) Snapshot(ctx context.Context, subjectType, subjectID string, data map[string]any, causerID string) (*Version, error)

Snapshot stores a version (point-in-time snapshot) of a subject for restore.

func (*Service) Versions

func (s *Service) Versions(ctx context.Context, subjectType, subjectID string) ([]Version, error)

Versions lists snapshots for a subject, newest first.

type Version

type Version struct {
	ID          string   `db:"id" json:"id"`
	SubjectType string   `db:"subject_type" json:"subject_type"`
	SubjectID   string   `db:"subject_id" json:"subject_id"`
	Data        JSONText `db:"data" json:"data"`
	CauserID    string   `db:"causer_id" json:"causer_id,omitempty"`
	CreatedAt   string   `db:"created_at" json:"created_at"`
}

Version is a stored snapshot of a subject, used to restore prior state.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL