Audit Logging
TSKit records user actions to an audit log. This gives you a trail of who did what and when, useful for security, debugging, and compliance.
How it works
Section titled “How it works”The audit system has three parts:
- Facade (
lib/facades/audit.ts) - Theaudit.log()function you call from server functions. It automatically captures the IP address and user agent from the request headers. - Service (
services/audit.service.ts) - Handles insertion and querying of audit records. - Labels (
lib/audit-labels.ts) - Maps action strings to human-readable labels for the UI.
Logging an action
Section titled “Logging an action”Call audit.log() from any server function:
await audit.log({ actorId: context.user.id, action: 'billing.checkout.created', targetType: 'organization', targetId: context.organization.id, metadata: { planId: data.planId },})The ipAddress and userAgent fields are captured automatically - you don’t need to pass them.
Action naming
Section titled “Action naming”Actions use dot-notation following the pattern domain.resource.verb:
billing.checkout.createdbilling.subscription.cancelledbilling.plan.changedteam.member.invitedteam.member.removedteam.member.role_changedsettings.profile.updatedsettings.password.changedsettings.two_factor.enabledadmin.user.banned
The first segment (before the first dot) is treated as the domain. This is used for filtering in the UI.
Log entry fields
Section titled “Log entry fields”| Field | Type | Required | Description |
|---|---|---|---|
actorId | string | No | The user who performed the action |
action | string | Yes | Dot-notation action name |
targetType | string | No | Type of the target (e.g., “user”, “organization”) |
targetId | string | No | ID of the target |
metadata | object | No | Extra key-value data |
ipAddress | string | Auto | Captured automatically |
userAgent | string | Auto | Captured automatically |
Querying logs
Section titled “Querying logs”The query() function in services/audit.service.ts supports filtering and cursor-based pagination:
const result = await query({ actorId: userId, action: 'billing', // prefix match - finds all billing.* actions from: new Date('2024-01-01'), to: new Date('2024-12-31'), cursor: lastItemId, limit: 50,})// { items: AuditLog[], nextCursor: string | null }Where logs are shown
Section titled “Where logs are shown”Audit logs are displayed in two places:
- Admin dashboard at
/admin/audit- All audit logs across the app, accessible to admins. - User settings at
/settings/activity- The current user’s own activity log.
Key files
Section titled “Key files”| File | Purpose |
|---|---|
lib/facades/audit.ts | Audit facade with auto IP/UA capture |
lib/audit-labels.ts | Human-readable labels for action strings |
services/audit.service.ts | Log insertion and querying |
database/schemas/audit.ts | Audit log table schema |