Skip to main content
Audit logs become weak when every service invents its own names and metadata shape. Start with a small catalog and grow it deliberately.

Define events

import { defineLodgerEvents } from "@lodger/sdk"

export const auditEvents = defineLodgerEvents({
  "account.user.login": {
    targetType: "account",
    userVisible: true,
  },
  "organization.member.removed": {
    targetType: "organization_member",
  },
  "billing.invoice.paid": {
    targetType: "invoice",
    userVisible: true,
  },
})

Use the catalog

const audit = lodger.withCatalog(auditEvents)

await audit.event("billing.invoice.paid", {
  actor: { id: "billing-worker", type: "service" },
  target: invoice.id,
  metadata: {
    amount: invoice.amount_paid,
    currency: invoice.currency,
  },
})
If target is a string, the SDK uses the catalog targetType. The catalog also supplies the default userVisible value.

Naming

Use dot-separated past-tense names:
  • account.user.login
  • organization.member.removed
  • policy.consent.accepted
  • billing.invoice.paid
Avoid names like update, changed, or event. Reviewers need to understand the action without opening raw metadata.

Metadata

Keep metadata structured and reviewable:
metadata: {
  organizationId: organization.id,
  reason: "Inactive contractor",
  relatedReceiptIds: [inviteReceipt],
}
Use relatedReceiptIds or relatedEventIds when one record depends on another. Lodger stores consistency hints inside the hashed payload.