Namespaces
Logical scoping unit across terms, tags, data sources, collectors, and entity groups — covers the CRUD lifecycle, the four-sister-service auto-create side-door, and the audit-silence caveat.
A Namespace is a logical scoping unit applied across the catalog's taxonomy and resource graph. Every Term and Tag carries an optional namespace; every Data Source and Collector binds to one; Data Entity Groups can inherit a namespace through their parent. Namespaces are the catalog-side analogue of a team-or-domain label — operators use them to keep two teams' "customer" terms from colliding, to keep two teams' data sources visually separated in the catalog, and to scope collector ingestion to a known taxonomy.
This page covers the create / update / soft-delete / list lifecycle, the three permission gates, the cascade-on-delete contract, the case-sensitivity rule, the audit-silence shape Namespace CRUD shares with Owners, and the four-sister-service auto-create side-door that mints namespace rows without NAMESPACE_CREATE.
Where to find it
Open the Management page → Namespaces tab. The page lists every namespace with a pagination header and a free-text filter; the right-side panel renders the create form. Operators with NAMESPACE_CREATE see the Add namespace affordance; operators with NAMESPACE_UPDATE see an in-place edit on each row; operators with NAMESPACE_DELETE see a remove affordance.
Lifecycle
Five operations exist on the Namespace surface:
List namespaces (paginated, optional query substring filter)
GET /api/namespaces
Any authenticated user; anonymous under DISABLED
Get a single namespace
GET /api/namespaces/{id}
Any authenticated user; anonymous under DISABLED
Create a namespace
POST /api/namespaces
NAMESPACE_CREATE
Update a namespace
PUT /api/namespaces/{id}
NAMESPACE_UPDATE
Soft-delete a namespace
DELETE /api/namespaces/{id}
NAMESPACE_DELETE
The read endpoints are not gated by a custom-permission entry — the platform's security wiring leaves them at the default .authenticated() level. Under auth.type=DISABLED they are reachable anonymously (see DISABLED authentication).
Case sensitivity
Namespace names are case-sensitive. finance and Finance are two distinct rows in the namespace table — an operator who creates Finance and a teammate who creates finance end up with two parallel namespaces that share no relations. The list endpoint's query parameter applies a case-insensitive substring match for the suggestion list, but resolution against the canonical row is by exact-string match.
Treat namespace names as a controlled vocabulary that benefits from a documented naming convention — snake_case and lowercase-with-hyphens are both common in deployments we have seen. Drift between case-variants is one of the most common Namespace-directory pollution shapes.
Soft-delete and reincarnation
The Namespace delete path is a soft delete — the DELETE /api/namespaces/{id} endpoint sets deleted_at = NOW() on the row rather than removing it from the table. The namespace table carries a partial-unique index on name that scopes uniqueness to rows where deleted_at IS NULL; after a soft-delete, the name slot is free and an operator can create a new namespace with the same name. The previously-deleted row is preserved with its original id; downstream auditing tables that reference the namespace by id retain their integrity.
The reincarnation pattern is operationally useful for "reset this namespace" workflows — an operator who wants to clear a namespace's history can soft-delete it and immediately create a new namespace with the same name. The new namespace has a different id; any prior relations (terms, data sources, collectors) remain attached to the soft-deleted row and do not migrate.
Cascade-on-delete guard
Namespace delete is blocked when any of four referent tables still reference the namespace. The platform's service layer zips four existence-predicates and rejects the operation if any returns true:
data_source (live rows)
A Data Source registered under this namespace
Re-assign the source to a different namespace via Management → Datasources, or remove the source entirely
collector (live rows)
A Collector registered under this namespace
Re-assign the collector or remove it via Management → Collectors
term (live rows)
A Glossary Term scoped to this namespace
Re-assign or delete the term via the Business Glossary
data_entity (non-deleted rows)
A live data entity ingested under this namespace
Re-configure the collector's namespace_name and re-ingest, or soft-delete the entities
When any predicate returns true, the platform returns CascadeDeleteException (HTTP 400, error code USR004) and the namespace remains live. The error message reads "Namespace cannot be deleted: there are still resources attached" — it does not enumerate which of the four classes is blocking the delete. The operator has to walk each referent class themselves.
The cascade guard is best-effort, not transactional. The delete path is not wrapped in a transaction, so the four existence-checks and the soft-delete that follows run as separate statements at READ COMMITTED with no lock held on the namespace. If a new referent — a data source, collector, term, or ingested data entity scoped to this namespace — is created in the brief window after the checks pass and before the soft-delete commits, the delete still succeeds and the new referent is left pointing at a soft-deleted namespace. This is a race only under concurrent writes (an operator deleting a namespace at the same moment another operator or a collector ingest attaches something to it); for the common case of a single operator clearing referents by hand it behaves exactly as the table above describes. If you need a hard guarantee, quiesce writes to the namespace before deleting it.
Auto-create side-door
The Namespace surface carries a load-bearing structural quirk: four sister services on the platform mint Namespace rows through the side-door NamespaceServiceImpl.getOrCreate(name) when their request body carries a non-empty namespace_name field. The four callers are:
Data Source service
POST /api/datasources, PUT /api/datasources/{id}
DATA_SOURCE_CREATE, DATA_SOURCE_UPDATE
Term service
POST /api/terms
TERM_CREATE
Collector service
POST /api/collectors
COLLECTOR_CREATE
Data Entity Group service
POST /api/dataentitygroups
DATA_ENTITY_GROUP_CREATE
Each of these calls getOrCreate(name), which does getByName(name).switchIfEmpty(createByName(name)) — the service silently inserts a new Namespace row if the name does not already exist. The caller does not need to hold NAMESPACE_CREATE; holding any one of the four parent permissions is sufficient to mint a Namespace row that becomes immediately visible to every authenticated user via the catalogue read.
The four-sister-service side-door collapses NAMESPACE_CREATE with four parent permissions. Operators expecting NAMESPACE_CREATE to be the gate for namespace creation — as the Permissions page describes it — discover the side-door when their namespace directory proliferates with junk rows (typos, organic operator typing of distinct strings for the same intent through one of the four side-door endpoints).
Mitigation today. Treat DATA_SOURCE_CREATE, DATA_SOURCE_UPDATE, TERM_CREATE, COLLECTOR_CREATE, and DATA_ENTITY_GROUP_CREATE as implicitly granting namespace-creation rights when their request bodies carry namespace_name. Audit the Namespaces list growth on a cadence — typo-introduced duplicates and case-variants are the most common operator-visible drift shape (see Case sensitivity above). If strict separation between Namespace creation and the four sister-service operations is a deployment requirement, treat the namespace_name form field as a closed allowlist at the network-perimeter layer rather than relying on platform RBAC.
The side-door is not a candidate for a one-commit upstream fix — closing it would either break the existing collector-ingestion workflow (which currently expects the side-door for first-time namespace bootstrap), or require a finer-grained NAMESPACE_CREATE_VIA_RESOURCE permission that adds UX complexity. Both are product-level decisions; the operator-side caveat is the right immediate ship.
A related sibling pattern exists on the Owner surface — Owner CRUD has its own side-door cluster through three resource-creation endpoints. The Namespace cluster is the canonical example because four distinct sister services touch it, but the architectural pattern (auto-create on getOrCreate(name)-style helpers) is general.
Activity trail
Namespace CRUD emits no Activity Feed event. Two independent facts of the platform's design both block it:
No event type exists. The Activity Feed's event-type catalogue has no
NAMESPACE_*member at all — there is simply no type the platform could emit for a namespace create, update, or delete.The activity table requires a data-entity anchor. Even if an event type existed, the activity table is schema-anchored to
data_entity_id NOT NULL— every emitted event must reference a single data entity (see Activity Feed → Scope). Namespace lifecycle operations have no data-entity anchor.
Closing one of these alone would not make Namespace CRUD auditable; both would have to change. The same shape applies to Owner CRUD, Role CRUD, Policy CRUD, and every other RBAC and taxonomy mutation; see Audit trail scope for the platform-wide audit-coverage matrix and the compensating-controls catalogue.
For compliance regimes that need who-changed-what-when on Namespaces, instrument the audit externally — an API-gateway access log records every authenticated mutation on /api/namespaces*; the PostgreSQL WAL via pgaudit records the namespace row writes. The audit-of-occurrence lives outside the platform until both the missing event type and the schema-tier data_entity_id NOT NULL anchor are addressed.
Where to next
Management — the parent page; covers the tab-visibility model and the read-collaborative posture across the eight non-Associations Management areas.
Permissions — the canonical home for
NAMESPACE_CREATE,NAMESPACE_UPDATE,NAMESPACE_DELETEand the four sister-service permissions the side-door collapses against.Activity Feed → Scope — the canonical home for the audit-silence pattern Namespace CRUD shares with Owners, Roles, and Policies.
Audit trail scope — the compliance-facing summary of what the platform audits today and the external instrumentation patterns for the silent-mutation surfaces.
Business Glossary, Manual Object Tagging — the two taxonomy surfaces that scope themselves to a Namespace; one canonical place to clear referents when preparing for a Namespace delete.
Last updated