Skip to main content

kysera audit

Audit logging and history tracking commands for viewing, managing, and analyzing audit logs.

Commands​

CommandDescription
initGenerate a migration that creates the audit table
logsQuery audit logs with filters
historyShow entity history timeline
restoreRestore entity from audit log
statsAudit log statistics
cleanupClean up old audit logs
compareCompare entity versions
diffShow differences between versions

init​

Generate a migration that creates the audit log table — the schema-managed alternative to letting @kysera/audit auto-create the table on first use.

kysera audit init

Options​

OptionDescription
--table <name>Audit table name (default: from config or audit_logs)
--dialect-ddlEmit dialect-tuned DDL instead of the plugin's portable schema
-d, --dir <path>Migrations directory (default: from configuration)
-c, --config <path>Path to configuration file

Portable vs Dialect-Tuned DDL​

By default the migration matches the portable schema the plugin auto-creates: TEXT columns everywhere, JSON payloads stored as serialized text, changed_at as an ISO-8601 string. That works identically on PostgreSQL, MySQL, and SQLite.

--dialect-ddl trades portability for queryability on the configured dialect:

DialectTuned typesExtras
PostgreSQLJSONB payloads, TIMESTAMPTZ, IDENTITY primary keyIndexes on (table_name, entity_id) and changed_at
MySQLJSON payloads, DATETIME(3), AUTO_INCREMENTSame indexes
SQLitePortable types (TEXT is native anyway)Same indexes

The plugin writes the same values either way (JSON strings and ISO timestamps are coerced by the database) — but a dialect-tuned migration is tied to that dialect. --dialect-ddl requires database.dialect in your configuration.

Example​

$ kysera audit init
Migration created: 20260802140538_create_audit_logs.ts
/work/my-app/migrations/20260802140538_create_audit_logs.ts
Run 'kysera migrate up' to create the 'audit_logs' table

The command respects global --dry-run (reports without writing) and global --json (emits { file, table, mode, dialect }, where mode is "portable" or "dialect"). It refuses to overwrite an existing migration file of the same name.

logs​

Query audit logs with flexible filtering options.

kysera audit logs [options]

Options​

OptionDescription
-t, --table <name>Filter by table name
-u, --user <id>Filter by user ID
-a, --action <type>Filter by action: INSERT, UPDATE, DELETE
-l, --limit <n>Limit number of results (default: 50)
--since <datetime>Show logs since datetime (ISO 8601)
--until <datetime>Show logs until datetime (ISO 8601)
-e, --entity-id <id>Filter by entity ID
--jsonOutput as JSON
-v, --verboseShow detailed information including changes
-c, --config <path>Path to configuration file
-s, --schema <name>PostgreSQL schema name (default: public)

Examples​

# View recent audit logs
kysera audit logs

# Filter by table
kysera audit logs --table users

# Filter by action type
kysera audit logs --action UPDATE

# Filter by user
kysera audit logs --user "admin-123"

# Filter by time range
kysera audit logs --since "2025-01-01T00:00:00" --until "2025-01-31T23:59:59"

# Filter by entity
kysera audit logs --table orders --entity-id "order-456"

# Verbose output with change details
kysera audit logs --table users --verbose

# Output as JSON
kysera audit logs --json

Output​

Table View (default):

IDTimeTableActionEntityUserChanges
1232025-01-15 10:00users~user-1admin3
1222025-01-15 09:45orders+order-5system-

Action symbols:

  • + INSERT (green)
  • ~ UPDATE (yellow)
  • - DELETE (red)

Verbose View (with --verbose):

Audit Log #123
--------------------------------------------------
Timestamp: 2025-01-15 10:00:00
Table: users
Action: UPDATE
Entity ID: user-1
User: admin

Changes:
email: "old@example.com" -> "new@example.com"
name: "Old Name" -> "New Name"
updated_at: 2025-01-14... -> 2025-01-15...

history​

Show the complete history timeline for a specific entity.

kysera audit history <table> <id> [options]

Arguments​

ArgumentDescription
tableTable name
idEntity ID

Options​

OptionDescription
-l, --limit <n>Limit number of results (default: 20)
--show-valuesShow changed values
--jsonOutput as JSON
--reverseShow oldest first (default: newest first)
-c, --config <path>Path to configuration file
-s, --schema <name>PostgreSQL schema name (default: public)

Examples​

# View entity history
kysera audit history users user-123

# Show with change details
kysera audit history users user-123 --show-values

# Show more history
kysera audit history orders order-456 --limit 50

# Chronological order
kysera audit history users user-123 --reverse

Output​

Entity History: users #user-123

Current State
{"id": "user-123", "email": "current@example.com", ...}

|- 2025-01-15 10:00:00 | UPDATE | admin
| Audit #123
| Changed fields:
| email: "old@example.com" -> "current@example.com"
|
|- 2025-01-10 14:30:00 | UPDATE | system
| Audit #120
| Changed fields:
| last_login: NULL -> 2025-01-10...
|
+- 2025-01-01 09:00:00 | INSERT | admin
Audit #100
Created with:
id: "user-123"
email: "original@example.com"
...

--------------------------------------------------
Summary:
Total Changes: 3
Time Span: 14 days, 1 hours
Actions: INSERT (1), UPDATE (2)
Top Users: admin (2), system (1)

restore​

Restore an entity to a previous state from audit log.

kysera audit restore <audit-id> [options]

Arguments​

ArgumentDescription
audit-idAudit log ID to restore from

Options​

OptionDescription
--dry-runPreview restore without executing
--forceSkip confirmation prompt
--jsonOutput as JSON
-c, --config <path>Path to configuration file

Examples​

# Preview restore
kysera audit restore 123 --dry-run

# Restore with confirmation
kysera audit restore 123

# Force restore without confirmation
kysera audit restore 123 --force

Output​

Restoring from Audit Log #123

Table: users
Entity ID: user-123
Restore Point: 2025-01-15 10:00:00

Changes to apply:
email: "current@example.com" -> "old@example.com"
name: "Current Name" -> "Old Name"

? Proceed with restore? (y/N)

stats​

Show audit log statistics and insights.

kysera audit stats [options]

Options​

OptionDescription
-t, --table <name>Filter statistics by table name
-u, --user <id>Filter statistics by user ID
-p, --period <duration>Time period: 1h, 1d, 1w, 1m (default: 1d)
-f, --format <type>Output format: table, json, chart (default: table)
-c, --config <path>Path to configuration file

Examples​

# Overall statistics for last day
kysera audit stats

# Statistics for last week
kysera audit stats --period 1w

# Statistics for specific table
kysera audit stats --table users

# Statistics for specific user
kysera audit stats --user "admin-123"

# Output as JSON
kysera audit stats --format json

# Statistics for last month as chart
kysera audit stats --period 1m --format chart

Output​

Audit Log Statistics
──────────────────────────────────────────────────

Time Range: 2025-01-01 to 2025-01-15

Total Entries: 15,432

By Action:
INSERT: 5,234 (33.9%)
UPDATE: 8,456 (54.8%)
DELETE: 1,742 (11.3%)

By Table:
orders: 8,234 (53.4%)
users: 4,567 (29.6%)
products: 2,631 (17.0%)

By User:
system: 9,000 (58.3%)
admin: 4,432 (28.7%)
api-user: 2,000 (13.0%)

Peak Activity:
Day: Monday (3,456 entries)
Hour: 14:00-15:00 (1,234 entries)

Storage:
Total Size: 45.2 MB
Avg Entry Size: 2.9 KB

cleanup​

Clean up old audit logs to manage storage.

kysera audit cleanup [options]

Options​

OptionDescription
--older-than <duration>Delete logs older than duration (30d, 3m, 1y)
-t, --table <name>Clean specific table only
--dry-runPreview cleanup without deleting
--forceSkip confirmation prompt
--batch-size <n>Delete in batches (default: 1000)
-c, --config <path>Path to configuration file

Examples​

# Preview cleanup of logs older than 90 days
kysera audit cleanup --older-than 90d --dry-run

# Clean logs older than 3 months
kysera audit cleanup --older-than 3m

# Clean specific table
kysera audit cleanup --table users --older-than 30d

# Force cleanup without confirmation
kysera audit cleanup --older-than 90d --force

# Cleanup in smaller batches
kysera audit cleanup --older-than 1y --batch-size 500

Output​

Audit Log Cleanup Preview
──────────────────────────────────────────────────

Criteria: Logs older than 90 days (before 2024-10-15)

Entries to delete:
users: 2,345 entries
orders: 5,678 entries
products: 1,234 entries

Total: 9,257 entries
Storage freed: ~26.8 MB

? Proceed with cleanup? (y/N)

compare​

Compare two versions of an entity.

kysera audit compare <id1> <id2> [options]

Arguments​

ArgumentDescription
id1First audit log ID
id2Second audit log ID

Options​

OptionDescription
--jsonOutput as JSON
--show-valuesShow full field values
-c, --config <path>Path to configuration file

Examples​

# Compare two audit entries
kysera audit compare 100 123

# Compare with full values
kysera audit compare 100 123 --show-values

# Output as JSON
kysera audit compare 100 123 --json

diff​

Show differences between entity versions.

kysera audit diff <table> <id> [from] [to] [options]

Arguments​

ArgumentDescription
tableTable name
idEntity ID
fromFrom audit log ID or timestamp (optional)
toTo audit log ID or timestamp (optional, default: current)

Options​

OptionDescription
--jsonOutput as JSON
-u, --unifiedShow unified diff format
--no-colorDisable colored output
-c, --config <path>Path to configuration file

Examples​

# Diff from specific audit to current
kysera audit diff users user-123 100

# Diff between two versions
kysera audit diff users user-123 100 123

# Unified diff format
kysera audit diff users user-123 100 --unified

# Output as JSON
kysera audit diff users user-123 100 123 --json

Requirements​

The query commands (logs, history, restore, stats, cleanup, compare, diff) work against the table @kysera/audit writes — columns operation, changed_by, and changed_at, with JSON payloads stored as text — on PostgreSQL, MySQL, and SQLite (existence is checked via database introspection, not information_schema). The table name follows plugins.audit.auditTable from your configuration (default audit_logs). If the table is missing you'll see a short setup hint instead of an error.

To set the table up, generate and run the migration:

kysera audit init
kysera migrate up

:::note Audit tables from Kysera versions before 0.9 Very old audit tables used the columns action, user_id, and created_at. The query commands now speak the current plugin schema (operation / changed_by / changed_at); against a pre-0.9 legacy table they will fail with unknown-column errors. Migrate such tables by renaming the columns (e.g. ALTER TABLE audit_logs RENAME COLUMN action TO operation, and likewise user_id → changed_by, created_at → changed_at). :::

See Also​