> For the complete documentation index, see [llms.txt](https://docs.opendatadiscovery.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.opendatadiscovery.org/features/active-platform-features/activity-feed.md).

# Activity Feed

Track changes to your data entities by monitoring the global **Activity** page or the **Activity** tab on a data entity's detail page. Every metadata edit the platform observes — entity lifecycle transitions, ownership changes, tag and term assignments, dataset-field edits, alerts — emits a typed event onto the feed. The feed is the catalog's audit trail and the change-driven discovery surface: who did what to which entity, and when.

![](/files/FGiluwwMOYraX6fccjPd)

## Where to find it

* **Global Activity page** — top-level `Activity` entry in the platform's navigation. Shows every event across the catalog with an eight-facet filter panel (see below) and a four-tab axis (`All` / `My Objects` / `Upstream Dependents` / `Downstream Dependents`).
* **Per-entity Activity tab** — every data-entity detail page has an `Activity` tab that scopes the feed to events on that entity only (plus a few additional internal event types — entity overview / metadata / schema / relation updates and custom-metadata create / update / delete — that are recorded on the per-entity tab but hidden from the global filter to keep that view concise). The per-entity tab does **not** carry the four-tab axis the global page exposes — see [Per-entity Activity tab differences](#per-entity-activity-tab-differences) below for the asymmetries you'll hit if you navigate between the two.

## My Objects setup (user-owner association prerequisite)

The `My Objects`, `Upstream Dependents`, and `Downstream Dependents` tabs on the global Activity page narrow the feed to entities the signed-in user is bound to as an [Owner](/configuration-and-deployment/enable-security/authorization/owners.md). The binding lives in the platform's `user_owner_mapping` table; without a row in that table the platform cannot answer the question "what changed on the things you own" — the three personalised tabs silently render an empty feed.

The binding is created in **Management → Associations** and the workflow is documented at [Authorization → User-owner association](/configuration-and-deployment/enable-security/authorization/user-owner-association.md). The same prerequisite applies to the [Alerts → My Objects](/features/active-platform-features/alerting.md) tab.

{% hint style="info" %}
**Pre-flight checklist for platform admins.** If you are setting up Roles, Policies, and Owners for other people and your own `My Objects` tabs (here on Activity, on Alerts, on the recommended entities surface) render empty even though the catalog is populated, you likely have **no `user_owner_mapping` for your own account**. Adding yourself as an owner on the entities you want surfaced — Management → Associations → Create association — fixes the silent-empty failure mode without changing anyone else's access.
{% endhint %}

## Filters on the global Activity page

The Filters panel on the Activity page lets you narrow the feed by eight facets:

* **Calendar** — restrict to a date / date-range window.
* **Datasource** — limit to events on entities from a specific datasource.
* **Namespace** — limit to events on entities in a given namespace.
* **Event type** — pick a single event type from the enumeration in the next subsection (e.g. `OWNERSHIP_CREATED`, `OPEN_ALERT_RECEIVED`).
* **Tag** — show events on entities carrying one or more selected tags (multi-select).
* **Owner** — show events on data entities owned by one or more selected owners (multi-select) — the owner of the **affected asset**, not the person who made the change. Useful for "what happened to my team's data this week".
* **Made by (owner)** — show events **performed by** users currently associated with one or more selected owners. ODD maps each user to an [Owner](/configuration-and-deployment/enable-security/authorization/user-owner-association.md), and this facet uses that *current* association — so re-associating an owner changes which past events match. The dropdown lists Owners.
* **Made by (user)** — show events **performed by** one or more selected users, identified by their external username (the `created_by` actor recorded on each event). This is **immutable** — it always reflects who actually made the change — and it works even for users with **no** owner association. The dropdown lists the usernames seen in the feed.

{% hint style="info" %}
**Owner, Made by (owner), and Made by (user) answer three different questions** — the owner of the affected *asset*, the *current* owner associated with whoever made the change, and the *immutable* external username of whoever made the change. Each facet carries an **ⓘ** help tooltip that spells out exactly what it matches, and the **Made by (user)** dropdown lists the raw usernames (exactly the values it filters on). Every event row shows the **username** of whoever made the change plus, when that user has an owner association, their **current owner** (rendered as "alice — current owner: Team A"). The owner shown is the association *as of now*: ODD does not record the owner association at the time of the change, so an old event reflects the user's present owner — not necessarily who they were associated with when they made it.
{% endhint %}

## Event types

The **Event type** filter on the global Activity page exposes the following event types, grouped here by the area of the metadata they describe.

**Data entity lifecycle**

* `DATA_ENTITY_CREATED` – a data entity was created in the platform.
* `DATA_ENTITY_STATUS_UPDATED` – an entity's status changed (`UNASSIGNED`, `DRAFT`, `STABLE`, `DEPRECATED`, `DELETED`). This is the event to filter on to find entity deletions — there is no separate "deleted" event type.
* `BUSINESS_NAME_UPDATED` – the business name of an entity was edited.
* `DESCRIPTION_UPDATED` – the description of an entity was edited.

**Ownership**

* `OWNERSHIP_CREATED` – an owner was added to a data entity.
* `OWNERSHIP_UPDATED` – an owner's role on a data entity was changed.
* `OWNERSHIP_DELETED` – an owner was removed from a data entity.

{% hint style="warning" %}
**Owner changes on a Data Entity Group cascade to the group's members, but only the group emits an event — the member entities do not.** When you add or remove an owner on a [Data Entity Group](/features/data-discovery/groups-domains.md), the platform propagates that ownership to every member entity (each member silently gains or loses the owner). The feed records a single `OWNERSHIP_CREATED` / `OWNERSHIP_UPDATED` / `OWNERSHIP_DELETED` event on the **group**; the per-member ownership writes emit **no event**. An auditor asking "when did this child entity gain owner X" by reading the child's Activity tab sees nothing — the change has to be inferred from the parent group's event and its membership at that time. If you need a per-entity audit of cascaded ownership, reconstruct it from the group event plus the group's member list, or instrument it at the database layer.
{% endhint %}

**Tags and terms**

* `TAG_ASSIGNMENT_UPDATED` – tags on a data entity were added, removed, or changed. Carries before-and-after tag lists.
* `DATASET_FIELD_TAGS_UPDATED` – tags on a dataset field (column) were added, removed, or changed. Carries before-and-after tag lists.
* `TERM_ASSIGNMENT_UPDATED` – terms linked to a data entity were added, removed, or changed.

{% hint style="warning" %}
**Tag-change events are non-uniform across the three tag-assign endpoints.** Data-entity tag changes emit `TAG_ASSIGNMENT_UPDATED` and dataset-field (column) tag changes emit `DATASET_FIELD_TAGS_UPDATED` — both carry the full before-and-after tag lists; **term tag changes emit no activity event at all today**. An auditor querying "who changed which tags when" must compensate for term tag changes by polling the term's current tag list and diffing externally. See [Manual Object Tagging → Known limitations and operator caveats](/features/data-discovery/tagging.md#known-limitations-and-operator-caveats) for the full operator framing.
{% endhint %}

**Dataset fields (columns)**

* `DATASET_FIELD_VALUES_UPDATED` – enum values configured on a dataset field were edited.
* `DATASET_FIELD_DESCRIPTION_UPDATED` – a field's description was edited.
* `DATASET_FIELD_INTERNAL_NAME_UPDATED` – a field's internal (user-defined) name was edited.
* `DATASET_FIELD_TAGS_UPDATED` – tags on a dataset field were added, removed, or changed.
* `DATASET_FIELD_TERM_ASSIGNMENT_UPDATED` – terms linked to a dataset field were added, removed, or changed.

**Data entity groups**

* `CUSTOM_GROUP_CREATED` – a custom [data entity group](/features/data-discovery/groups-domains.md) was created.
* `CUSTOM_GROUP_UPDATED` – the members or metadata of a custom group were changed.

{% hint style="warning" %}
**DEG-membership mutations (add / remove an entity from a DEG) emit no Activity Feed event.** The `CUSTOM_GROUP_UPDATED` event above fires only when the DEG's own metadata (description, tags, owners, terms) is edited, not when the membership set changes. The two membership-write endpoints (`POST /api/dataentities/{id}/data_entity_group` + `DELETE /api/dataentities/{id}/data_entity_group/{group_id}`) emit nothing — `DATA_ENTITY_RELATION_UPDATED` exists in the enum but is a dead value not triggered by any code path today. Auditors querying activity for a DEG's membership history must instrument it externally. See [Data Entity Groups & Domains → Managing DEG Membership](/features/data-discovery/groups-domains.md#managing-deg-membership) for the operator workflow and the mitigation list.
{% endhint %}

**Alerts**

* `OPEN_ALERT_RECEIVED` – a new alert was opened for a data entity. Driven by the [Alerting](/features/active-platform-features/alerting.md) subsystem.
* `RESOLVED_ALERT_RECEIVED` – an existing alert was resolved.
* `ALERT_STATUS_UPDATED` – the status of an alert was changed manually.
* `ALERT_HALT_CONFIG_UPDATED` – the [per-entity alert halt configuration](/features/active-platform-features/alerting.md#halt-notifications-per-entity) was changed.

{% hint style="info" %}
The platform emits a few additional internal event types (entity overview / metadata / schema / relation updates) that are recorded on the entity's own Activity tab but are intentionally hidden from the global Activity filter to keep the feed concise.
{% endhint %}

{% hint style="warning" %}
**Custom-metadata mutations (create / update / delete a field value on an entity) emit no Activity Feed event today.** The `CUSTOM_METADATA_CREATED`, `CUSTOM_METADATA_UPDATED`, and `CUSTOM_METADATA_DELETED` values exist in the `ActivityEventTypeDto` enum, but no code path emits any of them — they are dead values, same shape as the `DATA_ENTITY_RELATION_UPDATED` DEG-membership case above. An entity's Activity tab will not show metadata-value changes. For compliance teams that need a who-changed-what-when audit on metadata mutations, instrument externally — see [Custom metadata → Known limitations](/features/data-discovery/custom-metadata.md#known-limitations-and-operator-caveats) and [Audit trail scope](/configuration-and-deployment/enable-security/audit-trail-scope.md) for the compensating-controls catalogue.
{% endhint %}

{% hint style="warning" %}
**Scope: the Activity Feed is structurally data-entity-only.** The activity table's primary foreign key — `activity.data_entity_id` — is `NOT NULL`, which means **every emitted event is anchored to a single catalog data entity**. RBAC mutations (Policy / Role / Permission CREATE / UPDATE / DELETE), Owner CRUD, Term CRUD, Namespace CRUD, Datasource registration, Collector token rotation, and the Integration Wizard's configuration writes have no data-entity to anchor against and therefore **cannot emit even if a future code change tried to annotate them**. The schema, not just the absence of `@ActivityLog` annotations, blocks platform-wide audit on the feed.

For compliance teams that need RBAC / lifecycle / configuration audit, this is the absence the platform-side instrumentation does not fill — operators wire external audit at the layer that **can** see the change: an API-gateway access log (records every authenticated mutation), the PostgreSQL WAL via `pgaudit` (records every SQL write), or the application log if the JVM is run with the appropriate framework. For the full audit-vs-no-audit picture and the compensating-controls catalogue, see [Audit trail scope](/configuration-and-deployment/enable-security/audit-trail-scope.md).
{% endhint %}

## Known caveats

A few behaviours of the Activity Feed are non-obvious from the page above. Each item below states what an operator might assume, what the platform actually does, and what to do today.

{% hint style="warning" %}
**By default, every authenticated user reads every entity's activity history.** The repository query behind the global feed has no per-owner predicate — the `All` tab is a cross-team feed. The `My Objects` / `Upstream Dependents` / `Downstream Dependents` tabs scope by entity-ownership (the entities the signed-in user is bound to as an Owner), not by actor-axis (events the signed-in user performed). Treat the Activity Feed as catalog-read-collaborative — anyone who can read the catalog can read every team's activity history. If your deployment requires per-team audit isolation, enforce it at the network perimeter rather than relying on platform RBAC on this surface.
{% endhint %}

{% hint style="warning" %}
**Under `auth.type=DISABLED`, mutations are attributed to no actor and render visually identical to system events.** Anonymous callers under DISABLED mode trigger activity events whose `created_by` column is null; the UI shows these alongside the auto-resolved-alert-style "system event" lozenge. An auditor walking a DISABLED-mode feed cannot distinguish "anonymous user did X" from "platform did X." DISABLED mode is non-production by design (see [DISABLED authentication](/configuration-and-deployment/enable-security/authentication/disabled-authentication.md)); the Activity Feed's null-actor rendering is one more reason not to run DISABLED in production.
{% endhint %}

{% hint style="warning" %}
**A failure writing the activity event rolls back the change the operator was making.** The event is emitted inside the same database transaction as the metadata mutation that triggered it — the platform runs the originating write (an ownership change, a description edit, a tag assignment) and the activity-event insert atomically. If the activity insert fails for any reason (a transient database error, a connection drop mid-write), the **whole transaction rolls back**: the operator's change is reverted and the request returns `500` with no indication that the mutation was undone. This is the opposite of the usual "audit-or-warn" expectation — here the audit write is load-bearing for the mutation itself, not a fire-and-forget side channel. In practice this is rare and self-correcting (retry the edit), but operators debugging a "my change didn't stick and I got a 500" report should know the activity-feed write is in the critical path.
{% endhint %}

## Per-entity Activity tab differences

The per-entity `Activity` tab on a data-entity detail page exposes a smaller filter surface than the global Activity page does:

| Feature                                        | Global Activity page                                                   | Per-entity Activity tab                                   |
| ---------------------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------- |
| Tab axis                                       | `All` / `My Objects` / `Upstream Dependents` / `Downstream Dependents` | None — the tab is implicitly "all events for this entity" |
| Calendar filter                                | Yes                                                                    | Yes                                                       |
| Event type filter                              | Yes                                                                    | Yes                                                       |
| Made by (owner) filter (actor's current owner) | Yes                                                                    | Yes                                                       |
| Made by (user) filter (external username)      | Yes                                                                    | Yes                                                       |
| Datasource / Namespace / Tag / Owner filters   | Yes                                                                    | No (the entity is already fixed)                          |

The per-entity tab is the right surface for "what changed on this one entity, in this window" investigations; the global page is the right surface for "what changed across the catalog this week."

{% hint style="warning" %}
**The per-entity Activity tab is reachable for any data entity, including soft-deleted ones.** The route mounts without a permission gate or status-restriction; the underlying read endpoint applies no per-owner scoping. Any authenticated user can navigate to `/dataentities/{id}/activity` for any catalogued entity, and the tab returns the audit history even when the entity's status is `DELETED` (the catalog list endpoints hide soft-deleted entities, but the activity tab does not). Multi-tenant deployments expecting per-team isolation on entity-level audit history cannot enforce it on this surface today. The same cross-channel read posture applies to other per-entity read surfaces (see [Search and Filtering → Facet aggregators](/features/data-discovery/search.md#facet-aggregators-enumerate-cross-owner-data-by-default) for the wider pattern).
{% endhint %}

## Auto-resolved alert events

Auto-resolution events emitted from the [Alerting](/features/active-platform-features/alerting.md) subsystem are recorded as system events on the feed (no operator identity attached); manually-resolved alerts carry the operator's identity. This lets a reader walking the feed distinguish between alerts that were worked on by a human and alerts that simply cleared themselves on the next ingest.

## Configuration

Activity-feed **partitioning** is controlled by the platform-level setting [`odd.activity.partition-period`](/configuration-and-deployment/odd-platform.md#activity-feed-partitioning-odd-activity-partition-period) (default 30 days) on [Configure ODD Platform](/configuration-and-deployment/odd-platform.md). The key sets the **width** of each time partition on the `activity` table — it controls how the data is chunked, not how long it is kept. Adjust the partitioning cadence per the volume your deployment generates — the operator-side reference is the canonical home for this key.

{% hint style="warning" %}
**`odd.activity.partition-period` is not a retention window — the Activity Feed has no automatic deletion and grows without bound.** The setting governs only the size of each table partition; the platform creates new partitions as time advances but never drops a partition that holds activity rows. The single housekeeping job that touches activity partitions drops only *empty* past partitions, which is a near-no-op on any steadily-used deployment. There is no `activity`-table entry in the platform's TTL configuration (unlike resolved alerts, search facets, and soft-deleted entities, which each have a housekeeping TTL). On a busy catalog the `activity` table grows monotonically; plan for it in your PostgreSQL capacity, and if you need to reclaim space, prune old partitions out-of-band at the database layer. Shrinking `partition-period` makes each partition smaller (so out-of-band pruning is finer-grained) but does not introduce any automatic deletion.
{% endhint %}

## Where to next

* For the alert events that source four of the feed's event types → [Alerting](/features/active-platform-features/alerting.md).
* For per-entity user-authored discussion threads (a per-entity event stream complementary to this system-emitted one) → [Data Collaboration](/features/active-platform-features/data-collaboration.md).
* For the data-entity-group events that power the catalog's group view → [Data Entity Groups & Domains](/features/data-discovery/groups-domains.md).
* For the activity-feed partition setting → [Configure ODD Platform → Activity-feed partitioning](/configuration-and-deployment/odd-platform.md#activity-feed-partitioning-odd-activity-partition-period).
