Owners
Owners are catalog-side data-steward identities, distinct from authenticated users. Reference for the Owner CRUD model, Owner roles, and the operator caveats around lifecycle and audit.
An Owner is a catalog-side identity that represents a data steward — a person, team, or service responsible for a data entity or term. Owners are distinct from the authenticated users who sign in to ODD Platform: a signed-in user binds to an Owner through the User-owner association workflow, and from that point on the user's actions on data entities (creating ownership, editing custom metadata, marking statuses) are attributed to the Owner rather than to the raw username.
This page is the operator's reference for the Owner model — what an Owner is, how Owners get created, how Owner roles work, and the known caveats around Owner CRUD that operators authoring deployment-time scripts or compliance-grade audit policies should understand.
What an Owner is
An Owner is a single row in the owner table with a name (free-text, unique among active Owners) and a deleted_at soft-delete marker. Each Owner can carry zero or more Owner roles (RBAC bundles defined on the Roles page) that grant the bound user catalog-wide permissions. Each Owner can be bound to at most one active user (the user-owner association is a one-to-one relation), and each user can be bound to at most one Owner.
Owners are the unit of ownership on data entities: an entity's ownership relation references an Owner row, not a user, so reassigning a user to a different Owner moves the user's perceived attribution across every entity without rewriting the entities themselves.
You can browse and manage Owners on the Management → Owners tab.

How Owners are created
There are three write-paths that produce a new row in the owner table. Two of them are the curated path (a deliberate operator action); the third is an emergent accretion path that operators should be aware of when modelling their deployment's Owner directory.
Operator-curated (the
OWNER_CREATEpath). An operator with theOWNER_CREATEpermission uses the Create owner affordance on Management → Owners, orPOST /api/owners. The form fields arenameand an optionalroleslist. This is the path documented in operator playbooks and the path most deployments use during initial setup.User self-service via the home-page widget. When a signed-in user reaches the Owner-association widget and types an owner name that does not exist in the directory, the platform creates the Owner row on submit (the freeSolo +
OwnerService.getOrCreatecomposition described under Choosing an owner name). The user's request then enters the standard self-request / admin-approve flow. NoOWNER_CREATEpermission is required of the requester — the creation rides on the request submission.Admin auto-approve via
DIRECT_OWNER_SYNC. A user holding theDIRECT_OWNER_SYNCpermission can mint a brand-new Owner name and self-bind in a single POST — see How DIRECT_OWNER_SYNC changes the user-side flow. The Owner row is created on the requester's behalf with no admin review.
Beyond these three explicit paths, the platform's OwnerService.getOrCreate helper is also reachable from service-tier callers that take an owner-name string and need to attach the corresponding Owner row (entity-ownership creation, term-ownership creation). The auto-create behaviour there is detailed in the Lifecycle and known caveats section below.
Owner names accumulate over time
Because the free-text input on the home-page widget does not deduplicate against case or whitespace variants, the Owner directory naturally accretes near-duplicates (John Smith / john smith / John Smith with a trailing space) as new users sign in over the deployment's lifetime. The platform does not collapse these on read — john smith and John Smith are distinct Owners, each potentially bound to a different user, each potentially carrying different roles.
Operator hygiene recommendation: pick a stable owner-name convention for your deployment (canonical casing, no leading/trailing whitespace, no Unicode look-alikes) and communicate it to new users. Periodically audit Management → Owners for near-duplicates and merge or rename them. An operator with the OWNER_RELATION_MANAGE permission can also remove individual user-Owner bindings through the Active associations tab.
Owner roles
An Owner carries an optional list of roles — RBAC bundles defined on the Roles page. When a user is bound to an Owner, the Owner's roles supersede the user's auth-mode-derived roles for the purposes of catalog-side authorization. This is the platform's mechanism for granting a user catalog-wide permissions (browse-only, edit-glossary, manage-data-entities, etc.) that are independent of the user's identity-provider group memberships.
Attach roles to an Owner from the Management → Owners → Edit form. The ROLE_CREATE / ROLE_UPDATE / ROLE_DELETE permissions gate role management itself.
Owners on data entities
Ownership of a data entity is recorded as a relationship from the entity to one or more Owner rows, with an optional Owner role (the "title" of that ownership — for example, Steward, Subject Matter Expert, On-call). The relation is curated per-entity on the entity's detail page; the DATA_ENTITY_OWNERSHIP_CREATE / _UPDATE / _DELETE permissions gate those actions.
For the user-facing surface where ownership is curated and displayed, see the Data entity detail page → Permissions reference.
Lifecycle and known caveats
The Owners API surface and the Owner-CRUD service tier have four operator-visible behaviours that are not obvious from the per-page documentation alone. Each item below names what an operator might assume, what actually happens, and what to do today.
1. Owner CRUD events are not audited at the platform tier
The Owner service creates, updates, soft-deletes, and re-creates Owners inside a transactional context but emits no Activity Feed event on any of those operations. The activity table's schema requires a data_entity_id foreign key on every row — Owner CRUD has no data-entity context, so adding an activity emission to the existing stream would require a coordinated schema change. The owner_association_request_activity stream covers the request workflow (user submits → admin approves/denies) but not the Owner entity's own lifecycle.
Combined with the role-binding hard-delete on the Owner DELETE path and the partial-unique-index pattern that allows soft-deleted names to be re-used by a new Owner row, an operator can delete Alice, recreate a new Owner row with the name Alice, and there is no platform-visible record of the rename or the original deletion except the original row's deleted_at timestamp.
For compliance frameworks that require identity-change audit trails (SOX records of identity-management changes, NIST 800-53 AU-2 audit events), use one of the compensating controls in Audit trail scope → Compliance implications.
2. GET /api/owners is unauthenticated-read; every signed-in user enumerates the directory
GET /api/owners is unauthenticated-read; every signed-in user enumerates the directoryThe /api/owners endpoint's POST / PUT / DELETE verbs are each gated by an OWNER_* permission (see the table below), but the GET verb is not gated. There is no OWNER_READ permission anywhere on the platform; any authenticated user under LOGIN_FORM, OAUTH2, or LDAP can enumerate the entire Owner directory through GET /api/owners. Under auth.type=DISABLED the endpoint is anonymously reachable.
POST /api/owners
OWNER_CREATE
PUT /api/owners/{id}
OWNER_UPDATE
DELETE /api/owners/{id}
OWNER_DELETE
GET /api/owners
none — any authenticated user
This matches the platform's broader read-collaborative posture on Management catalogs: all Management read endpoints are reachable to any signed-in user by design. Deployments that need read-side isolation cannot achieve it through OWNER_* permissions today.
3. Three service-tier side-doors mint Owner rows without OWNER_CREATE
OWNER_CREATEIn addition to the three explicit Owner-creation paths described above, three other service-tier code paths reach OwnerService.getOrCreate and silently mint an Owner row when their input names one that does not exist:
POST /api/owner_association_request— the user-self-request endpoint (any authenticated user). Creating a request with a never-before-seen owner name creates the Owner row before the admin review starts.POST /api/dataentities/{data_entity_id}/ownership— gated byDATA_ENTITY_OWNERSHIP_CREATE. Attaching ownership to an entity with a brand-new owner-name string creates the Owner.POST /api/terms/{term_id}/ownership— gated byTERM_OWNERSHIP_CREATE. Attaching ownership to a glossary term with a brand-new owner-name string creates the Owner.
Operator consequence: an operator who grants DATA_ENTITY_OWNERSHIP_CREATE to a role expecting it to be a strict "attach to existing Owner" capability actually grants "mint Owner + attach" — the new Owner row appears in GET /api/owners immediately and persists across the rename or removal of the entity that triggered its creation. Monitor Owner-directory growth as part of your audit cadence; if OWNER_CREATE is reserved to a small operator group, also audit the three side-door endpoints for unintended Owner-name expansion.
4. PUT /api/owners/{id} with empty (or absent) roles silently destroys all role bindings
PUT /api/owners/{id} with empty (or absent) roles silently destroys all role bindingsThe OwnerFormData.roles field is marked optional in the OpenAPI spec, but the runtime treats absent-or-empty roles as a destructive update: the service helper collapses both null and [] to the empty list, the update transaction calls deleteOwnerRelationsExcept(ownerId, []) (which deletes every existing role-binding on this Owner because no existing binding is in the empty set), and then createRelations(ownerId, []) (which inserts nothing). The Owner persists; every role-binding is gone.
The UI's read-modify-write pattern always sends the current roles array in its PUT request, so the destructive path never surfaces through the Management UI for typical workflows. Direct-API consumers (Terraform providers, CI scripts, automation jobs) calling the endpoint with a partial body — for example, a rename — hit the destructive path on the first omission.
PUT /api/owners/{id} with body {"name": "new_name"} removes every role binding on the Owner. The OpenAPI spec presents roles as optional, but the runtime treats absent and empty identically. Always include the current roles array verbatim when issuing a PUT request, even for rename-only operations. A platform-side fix that adopts PATCH semantics (with null meaning "no change") or marks roles required is tracked upstream.
Safe-pattern code for direct-API consumers performing a rename:
The fetch-modify-write pattern preserves the existing roles array (and any other optional field with the same destructive semantic). UI workflows do not need this pattern — the Management UI already does the fetch-modify-write internally.
Operator-facing surfaces that depend on user-owner association
A signed-in user without a user_owner_mapping row sees every My-scoped surface render empty — the platform cannot answer "what changed on the things you own" without the binding. The personalised surfaces that depend on the association:
The Activity Feed's
My Objects/Upstream Dependents/Downstream Dependentstabs (see Activity Feed → My Objects setup).The Alerts page's
My Objects/Dependentstabs (see Alerting → Known UX limitations).The recommended-entities widgets on the catalog home page.
A platform admin who creates Owners and binds others without creating a mapping for their own account experiences these surfaces as silent-empty during onboarding — a common "platform is broken" first impression. Adding yourself as an Owner on the entities you want surfaced (Management → Associations → Create association) is the fix; the binding only affects what your account sees and does not change anyone else's access.
Where to next
User-owner association — the user-side workflow for binding to an Owner, the three write-paths in full, the admin operational surface, and the post-association lifecycle.
Roles — the RBAC bundle definitions that Owners can carry, and the precedence rules when an Owner role and a user-derived role both apply.
Permissions — the full enumeration of permission keys, including the
OWNER_*rows referenced above.Management → Owners — the operator UI tab where Owners are browsed, created, edited, and deleted.
Audit trail scope — for the broader picture of what the platform audits and the compensating controls for the negative-half subjects (RBAC, Owner, Term, Namespace, Datasource, Collector lifecycle).
Last updated