# Audit Log

> Audit trail entry with actor, resource, action, changes, and IP tracking.

- Name: `audit-log`
- Categories: logging
- Detail page: https://open-types.dev/types/audit-log

## Install

```bash
# Types only
npx shadcn add @open-types/audit-log

# Types + Zod v4 validators
npx shadcn add @open-types/audit-log-zod

# Types + real-world examples
npx shadcn add @open-types/audit-log-examples
```

## Types

```typescript
export type AuditLogAction = "create" | "read" | "update" | "delete";

export interface AuditLogChange {
  old?: unknown;
  new?: unknown;
}

export interface AuditLogEntry {
  id: string;
  action: AuditLogAction;
  actor_id: string;
  actor_type?: string;
  resource_type: string;
  resource_id: string;
  changes?: Record<string, AuditLogChange>;
  ip_address?: string;
  user_agent?: string;
  timestamp: string;
}
```

## Zod validator

```typescript
import * as z from "zod";
import type {
  AuditLogAction,
  AuditLogChange,
  AuditLogEntry,
} from "../types/audit-log";

export const auditLogActionSchema = z.enum([
  "create",
  "read",
  "update",
  "delete",
]) satisfies z.ZodType<AuditLogAction>;

export const auditLogChangeSchema = z.object({
  old: z.unknown().optional(),
  new: z.unknown().optional(),
}) satisfies z.ZodType<AuditLogChange>;

export const auditLogEntrySchema = z.object({
  id: z.string().min(1, { error: "Audit log ID is required" }),
  action: auditLogActionSchema,
  actor_id: z.string().min(1, { error: "Actor ID is required" }),
  actor_type: z.string().optional(),
  resource_type: z.string().min(1, { error: "Resource type is required" }),
  resource_id: z.string().min(1, { error: "Resource ID is required" }),
  changes: z.record(z.string(), auditLogChangeSchema).optional(),
  ip_address: z.string().optional(),
  user_agent: z.string().optional(),
  timestamp: z.iso.datetime({ error: "Invalid timestamp" }),
}) satisfies z.ZodType<AuditLogEntry>;

export type { AuditLogAction, AuditLogChange, AuditLogEntry } from "../types/audit-log";
```

## Examples

```typescript
// Source: hand-crafted
import type {
  AuditLogAction,
  AuditLogChange,
  AuditLogEntry,
} from "../types/audit-log";

export const auditLogActionExamples = {
  create: "create",
  read: "read",
  update: "update",
  delete: "delete",
} as const satisfies Record<string, AuditLogAction>;

export const auditLogChangeExamples = {
  oldAndNew: { old: "viewer", new: "admin" } satisfies AuditLogChange,
  newOnly: { new: "active" } satisfies AuditLogChange,
  oldOnly: { old: "draft" } satisfies AuditLogChange,
  empty: {} satisfies AuditLogChange,
} as const;

const updateEntry = {
  id: "audit_01HABCDEF0123456789ABCDE",
  action: "update",
  actor_id: "user_321",
  actor_type: "user",
  resource_type: "user",
  resource_id: "user_555",
  changes: {
    role: { old: "viewer", new: "admin" },
    isActive: { old: false, new: true },
  },
  ip_address: "203.0.113.42",
  user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
  timestamp: "2026-05-16T18:30:00Z",
} as const satisfies AuditLogEntry;

export const auditLogEntryExamples = {
  update: updateEntry,
  create: {
    ...updateEntry,
    id: "audit_create_001",
    action: "create",
    resource_id: "user_new_001",
    changes: { email: { new: "new@example.com" }, name: { new: "New User" } },
  } satisfies AuditLogEntry,
  delete: {
    ...updateEntry,
    id: "audit_delete_002",
    action: "delete",
    resource_id: "user_deleted_002",
  } satisfies AuditLogEntry,
  read: {
    ...updateEntry,
    id: "audit_read_003",
    action: "read",
    actor_type: "api_key",
    actor_id: "key_001",
  } satisfies AuditLogEntry,
  serviceAccount: {
    ...updateEntry,
    id: "audit_svc_004",
    actor_type: "service_account",
    actor_id: "svc_billing",
  } satisfies AuditLogEntry,
  minimal: {
    id: "audit_min_005",
    action: "read",
    actor_id: "user_321",
    resource_type: "report",
    resource_id: "report_001",
    timestamp: "2026-05-16T18:30:00Z",
  } satisfies AuditLogEntry,
} as const;
```
