# Audit log

> Around 210 recorded actions, append-only at the database level, with IP addresses stored as hashes.

The audit log records consequential actions across the organisation. Reading it
needs `audit.read`.

## What is recorded

Roughly **210 distinct actions**, named `<target>.<what>` or
`<target>.<noun>.<verb>`: `blueprint.acl.revoke`, `blueprint.visibility.update`,
`apikey.revoke`, `enterprise.scim.deprovision`.

They hang off twenty-one target types:

`blueprint` · `user` · `team` · `org` · `invite` · `setting` · `portfolio` ·
`portfolio_folder` · `portfolio_item` · `diagram` · `vellum_save` · `comment` ·
`license` · `template` · `folium` · `integration` · `cloud_connection` ·
`continuum_integration` · `enterprise_tenant` · `lead` · `lead_company`

Each entry records who acted, what they acted on, when, a structured diff of
what changed, and enough request context to tell one session from another.

> [!NOTE]
> The diff is capped at about **4 KB**. A large change is summarised rather
> than captured whole.

## What it does not keep

> [!IMPORTANT]
> The log stores a **hash** of the IP address, never the address itself, along
> with the user agent. That is enough to tell two sessions apart or spot an
> anomaly, without building up a record of where members live.

## Append-only, and enforced twice

No codepath in the application updates or deletes an audit row.

> [!IMPORTANT]
> The database also installs triggers that **raise on `UPDATE` and `DELETE`**
> against the table. If a future refactor introduced a bypass, Postgres stops
> it. No owner, admin or support path can rewrite this log.

## Enterprise actions are catalogued

Action strings are free-typed except in the `enterprise.*` namespace.
Thirty-five constants cover tenancy, contracts, SSO, SCIM, IP allow-listing,
classification, white-label domains, integrations and stack provisioning, so an
enterprise event cannot be recorded under a name that differs from the one you
are searching for.

## Teams

Teams have their own audit view scoped to their own content, so a team lead can
review their area without being granted organisation-wide `audit.read`.
