Skip to content

CDS annotation families

A CDS view is not just a data query. It is a query with metadata attached, and the metadata is what lets a single view be consumed by a dozen different runtimes — Fiori, an OData service, the analytic engine, Datasphere, the SAP Analytics Cloud live connection — without any of them having to invent their own schema.

The metadata is expressed as annotations. Each family of annotations targets a different runtime and answers a different question. Atlas reads all of them when it plans; it writes the ones that belong to the output type it is generating.

@VDM
→ VDM layer + role
Classifies the view: #BASIC / #COMPOSITE / #CONSUMPTION. Atlas uses this to place the view on the layer axis.
@VDM.viewType: #BASIC
@ObjectModel
→ RAP / object model
Declares text associations, representative keys, foreign-key links. Drives Fiori value-help and Atlas entity resolution.
@ObjectModel.text.association: '_Text'
@Analytics
→ analytic engine
Marks cubes, dimensions, queries. Atlas uses these to branch the plan into analytical vs transactional.
@Analytics.dataCategory: #CUBE
@Semantics
→ business semantics
Tags fields as amounts, quantities, dates, tax codes, currencies. Atlas trusts these when Evidence is tier-1.
@Semantics.amount.currencyCode: 'Currency'
@UI
→ Fiori generative UI
Line-item position, data-point criticality, selection fields, facets. Atlas surfaces these for the gate that checks UI coverage.
@UI.lineItem: [{ position: 10 }]
@OData
→ service binding
Publishes the view as an OData service. Modern S/4 replaces @OData.publish with service bindings; Atlas tracks both forms.
@OData.publish: true
@AccessControl
→ DCL enforcement
Forces an access-control check. A prerequisite for the authorization gate Atlas requires before a plan can be transported.
@AccessControl.authorizationCheck: #CHECK
@ChangeDataCapture
→ delta + Datasphere
Enables CDC streams out to Datasphere and Business Data Cloud. Atlas uses CDC presence as an evidence tier modifier.
@ChangeDataCapture.recommended: true

Think of a generated consumption view as a single row of JSON-LD traveling out of HANA to whoever asked for it. The annotations on the view say, for each field: this is an amount; its currency is in that other field; its label is this string; this is the text association that turns a key into a name. Different consumers read different subsets of the metadata and present the data accordingly.

Fiori reads @UI.lineItem to lay out the columns, @Semantics.amount to format numbers with the right currency symbol, and @ObjectModel.text.association to resolve keys into names. The analytic engine reads @Analytics.dataCategory to know whether a view is a cube or a dimension, and @Analytics.query: true to recognize a query specification. An OData consumer reads the service binding to discover endpoints. A compliance gate reads @AccessControl.authorizationCheck to confirm that row-level filters will actually run.

The point is that one view can serve all of them if the annotations are correct. The cost of getting them wrong is that some consumer quietly misinterprets the data — a currency is missing, a text is not resolved, a field is rendered as a raw number when it should be a timestamp.

Metadata travels with the data HANA COLUMN STORE NetAmount: 1,240.00 @Semantics.amount @UI.lineItem.position: 10 @ObjectModel.text.assoc value + 3 annotations OData ODATA SERIALIZER value is emitted as JSON metadata is emitted alongside, not dropped or translated away $metadata keeps the annotations HTTP FIORI CLIENT reads the annotations and renders accordingly: @Semantics.amount → €1,240.00 with symbol @UI.lineItem.position → column 10 of the table The annotations are the contract. Drop one and downstream consumers silently misread the data. This is why Atlas writes them explicitly, and why the generate-stage gates catch missing ones.
One field's journey — value and metadata travel together, from column store to screen.

Two failure modes are easy to reintroduce by hand. The first is missing annotations — you write a view, forget to mark an amount with its currency, and the Fiori renderer shows the number without a symbol. Downstream reports then misclassify the number. The second is contradictory annotations — a field marked as both a quantity and an amount, or a dimension marked as a cube. Each mistake usually surfaces on someone else’s dashboard weeks later.

Atlas writes every annotation its generator emits from an explicit evidence node. If a field is marked as an amount, there is an evidence node saying this is an amount because the source catalog labeled it as one. If the evidence weakens, the annotation is flagged for review. The gates that run on generate catch the structural contradictions — quantity-and-amount, dimension-and-cube — before they can reach validate.

The grid above is a map, not an index. For each family the reference has the full list of annotations, their allowed values, and the runtimes that consume them. If you find yourself wondering whether a specific annotation is safe to use or whether Atlas will emit it for you, that is the place to go.