Activity Feed
ODD Platform records every metadata change as a typed event on a global Activity feed and on per-entity Activity tabs — the catalog's audit trail and change-driven discovery surface.
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.

Where to find it
Global Activity page — top-level
Activityentry 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
Activitytab 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 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. 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. The same prerequisite applies to the Alerts → My Objects tab.
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, 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_byactor 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.
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.
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, 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.
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.
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 for the full operator framing.
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 was created.CUSTOM_GROUP_UPDATED– the members or metadata of a custom group were changed.
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 for the operator workflow and the mitigation list.
Alerts
OPEN_ALERT_RECEIVED– a new alert was opened for a data entity. Driven by the Alerting 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 was changed.
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 and Audit trail scope for the compensating-controls catalogue.
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.
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.
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.
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); the Activity Feed's null-actor rendering is one more reason not to run DISABLED in production.
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.
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:
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."
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 for the wider pattern).
Auto-resolved alert events
Auto-resolution events emitted from the Alerting 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 (default 30 days) on Configure ODD Platform. 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.
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.
Where to next
For the alert events that source four of the feed's event types → Alerting.
For per-entity user-authored discussion threads (a per-entity event stream complementary to this system-emitted one) → Data Collaboration.
For the data-entity-group events that power the catalog's group view → Data Entity Groups & Domains.
For the activity-feed partition setting → Configure ODD Platform → Activity-feed partitioning.
Last updated