Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions content/docs/api/data-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -420,16 +420,23 @@ Filtering uses the canonical Query DSL `where` object (the same MongoDB-style `F
```

<Callout type="info">
**`fields[]` describes columns, not presentation.** Each entry carries exactly `name` and
`type` — that is the whole descriptor `AnalyticsResultResponseSchema` declares, and every
strategy answering this endpoint emits those two keys and nothing else.

Display name and number format live one layer up, in the **cube's metric/dimension
definition** (`MetricSchema.label` / `MetricSchema.format`, `DimensionSchema.label`), and
are read from cube metadata — `GET /analytics/meta` below reports each measure's and
dimension's declared label as `title`. Reading `data.fields[i].label` or
`data.fields[i].format` off a query result yields `undefined`; a client that renders table
headers or formats amounts reads them from the cube metadata instead.
**`fields[]` is the resolved presentation surface — read it first.** Each entry carries
`name` and `type` and, when the producer declares them, `label`, `format`, `currency`,
`percentScale` and `builtinAggregate`: the optional members
`AnalyticsResultResponseSchema` declares (`packages/spec/src/api/analytics.zod.ts`),
mirrored member for member by `IAnalyticsService.query`'s `AnalyticsResult` and bound to
it at compile time. Optional means a given column may omit them — read them defensively,
never as guaranteed present.

The **cube's metric/dimension definition** (`MetricSchema.label` / `MetricSchema.format`,
`DimensionSchema.label`) is the *declaration* surface, not a substitute for this one.
`GET /analytics/meta` below publishes a deliberately narrow projection of it — `name`,
`type` and `title` (the definition's `label`) only, with `format` dropped
([#6442](https://github.com/objectstack-ai/objectstack/issues/6442)). So a client that
renders table headers or formats amounts takes `label` / `format` / `currency` /
`percentScale` off the query result's `fields[]`: those are resolved server-side (the
ADR-0053 currency chain, the percent-scale chain), and `format` is not reachable through
the metadata endpoint at all.
</Callout>

### `GET /analytics/meta`
Expand Down
22 changes: 17 additions & 5 deletions content/docs/kernel/services-checklist.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -607,12 +607,24 @@ When a plugin registers a service, the discovery endpoint automatically updates:
`route` → `"/api/v1/auth"` (unless the instance self-declares `stub`/`degraded` via
`__serviceInfo`, which is reported verbatim instead)
- `routes.auth` → `"/api/v1/auth"` appears in routes
- `features` flags follow for the slots that have one — `search`, `files`,
`analytics`, `ai`, `workflow`, `notifications`, `i18n` (`websockets` does **not**
follow slot presence: it is `isSubscribableChannel(services.realtime)` — `handlerReady:
- the `capabilities` entries derived from that slot flip — `files` (and
`chunkedUpload`, which rides the same storage surface), `analytics`, `ai`,
`notifications`, `i18n`, `automation`, `cron` (the `job` slot) and `export`
(`automation` **or** `queue`). `capabilities` is the canonical spelling: the top-level
`features` map was renamed to it in
[#4828](https://github.com/objectstack-ai/objectstack/issues/4828), and the `workflow`
slot was retired in v17 ([#4451](https://github.com/objectstack-ai/objectstack/issues/4451)),
so neither name is on the wire. The rest of the vocabulary does **not** follow slot
presence: `websockets` is `isSubscribableChannel(services.realtime)` — `handlerReady:
true` **and** a connectable route — so registering a realtime service does not flip it,
and it reads `false` on every host the open framework ships, #14646; there is no
`features.auth`)
and it reads `false` on every host the open framework ships, #14646; `search` is stated
`false` because this dispatcher mounts no `/search` route, whatever fills the slot
([#7602](https://github.com/objectstack-ai/objectstack/issues/7602)); `comments` is
measured from the object registry; and `transactionalBatch` is `false` on this face,
which mounts no `/batch`. There is no `capabilities.auth`: the vocabulary is closed by
`WellKnownCapabilitiesSchema` (`packages/spec/src/api/discovery.zod.ts`), every producer
answers every key, and a capability the host does not deliver reads `enabled: false`
rather than a missing key

---

Expand Down
Loading