Entity model¶
Entity model and System shape
This page describes the catalog's data model: the Catalog Entity kinds a distribution registers and their relationships. For the build and deploy pipeline that assembles and runs Atlas, see System shape.
Every Catalog Entity has a kind. Its fields determine which other entities it can reference. Standard Catalog, the plugin every distribution must select, registers five kinds. The optional APIs plugin registers a sixth:
| Kind (wire value) | Registered by | Declares | Notes |
|---|---|---|---|
system |
Standard Catalog | architecture.subject.v1 |
Groups Components, Resources, and APIs. Owned by exactly one Group. |
component |
Standard Catalog | architecture.subject.v1 |
A service, website, library, or worker. Belongs to one System. |
resource |
Standard Catalog | schema.host.v1 |
A database, cache, bucket, queue, or cluster. System is optional. |
api |
APIs (optional) | None | An OpenAPI, gRPC, AsyncAPI, or GraphQL contract. Belongs to one System. |
group |
Standard Catalog | architecture.actor.v1 |
A team, business unit, product area, or the root group. Has Actor members. |
user |
Standard Catalog | architecture.actor.v1 |
An Actor is a person, whether or not they can log in. Its Python identifier is Actor; its stored/wire kind is user. |
Atlas does not have a Domain kind that groups Systems as Backstage does. System is the highest
containment level. A capability such as architecture.subject.v1 lets a plugin like C4 target
"every kind that can appear as a diagram subject" without hard-coding kind == 'system' or kind == 'component'.
resource does not declare that capability: a Resource can appear inside a diagram but is not a
diagram subject.
Containment and ownership¶
Two structural relationships shape the taxonomy. Plain fields on each kind's spec drive both of them. See Entity references for how the resulting Relation rows are represented and queried.
- Ownership (
ownedBy/ownerOf): every System, Component, Resource, and API has exactly oneowner, which must resolve to agroupref. A Group is never itself owned, and an Actor has no owner concept.ActorSpecInhas noownerfield. - Containment (
partOf/hasPart): every Component and API belongs to exactly one System (systemis required on both); a Resource'ssystemis optional. A System does not belong to anything above it.
A Component also declares providesApis/consumesApis edges to api entities and a dependsOn
edge to resource entities. A Group declares a hasMember edge to user entities. These edges
describe interactions rather than structural containment.
flowchart TB
Group[Group] -- hasMember --> Actor[Actor / user]
System[System] -- ownedBy --> Group
Component[Component] -- ownedBy --> Group
Component -- partOf --> System
Component -- dependsOn --> Resource[Resource]
Component -- "providesAPI / consumesAPI" --> API[API]
Resource -- ownedBy --> Group
Resource -. partOf .-> System
API -- ownedBy --> Group
API -- partOf --> System
(Dotted edge: a Resource's system is optional; every other edge shown is required.)
Entity kinds by authoring path¶
- Ingestible kinds: System, Component, Resource, API, and User can be created manually through
the UI/API or by an ingestion pipeline that parses
catalog-info.yamlfiles. See Life of an entity for how the two paths interact. - Admin-managed kinds: Group is never ingestible. It exists only through Django admin or as
the
ownerreferenced by a manual or ingested entity. User is ingestible. Unlike the other four ingestible kinds, its spec has norelationshipsfield, so it can be a relationship target but cannot declare a relationship as a source.
A kind's fields are visible only through its own *Details model, apart from the identity row
shared by every kind. See the Catalog Entity and Entity Kind entries in the
domain glossary for that distinction.