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
43 changes: 43 additions & 0 deletions .changeset/19790-nav-doc-audience-prune.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
'@objectstack/rest': patch
---

fix(rest): `GET /meta/app` leaves out a `type: 'doc'` navigation entry the caller may not read (#19790)

`DocNavItemSchema` declares that a `doc` entry the member may not read is not
rendered, and that a `book` entry is not rendered for a member with no readable
page in it. Until now only a renderer could honour that. The server's app-nav
filter pruned on `requiredPermissions`, `requiresService` and object servability,
so every member of the app got the entry. That included its label and the gated
book or doc name, however the book was gated.

The filter now applies the docs audience (ADR-0046 §6.7) on both the list route
(`GET /meta/app`) and the by-name route (`GET /meta/app/:name`), in the top-level
navigation, inside `children` and inside `areas[].navigation`:

- **`doc`**: the entry is dropped when the doc's effective audience does not
admit the caller. This is the answer `GET /meta/doc/:name` gives.
- **`book`**: the entry is dropped when the book's own audience does not admit
the caller, or when none of its pages is readable. A book's pages are the docs
its groups claim. The *Uncategorized* group that the book tree adds does not
count.
- **`book` + `doc`**: the entry is dropped when either of those checks fails.
- An app emptied by the prune is still served, as it is today when
`requiredPermissions` empties one. An emptied `group` or area collapses, as
with every other gate.

The verdicts come from the same resolution that `/meta/doc`, `/meta/doc/:name`,
`/meta/book` and `/meta/book/:name/tree` now share. What those reads return is
unchanged.

**Fails closed.** If the book or doc list read throws while `/meta/app` is being
answered, every `doc` entry is left out of that one response and a warning is
logged. The rest of the navigation is still served. If the caller's
permission-set holdings cannot be resolved, set-gated entries are dropped, as
set-gated content already is.

**Cost.** An app list with no `doc` entry performs no extra read. Otherwise each
request adds one `book` list read, one permission-set resolution when some book
is set-gated, and one `doc` list read when a set-gated book exists or an entry
names only a book. Each of these happens once per request, however many apps are
listed. Nothing is cached across requests.
12 changes: 9 additions & 3 deletions content/docs/ui/apps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,15 @@ and an item with neither is refused with a message naming both keys:
- **Audience** — the entry has no gate of its own; it inherits the docs audience
gate. A `book` entry shows the member only the pages they may read, and is not
shown to a member with no readable page in it; a `doc` entry the member may not
read is not shown. The page content itself is gated on the server by the
`/meta/doc` and `/meta/book/:name/tree` reads. `visible` and
`requiredPermissions` still apply and can only narrow further.
read is not shown. The server applies this rule to the entry itself:
`/meta/app` leaves such an entry out of the app it returns, so its label and
its book or doc name never reach a member who cannot open it. An item with both
`book` and `doc` is also left out when the member may not open that book, even
if they may read the page. A book's pages are the docs its groups claim; the
*Uncategorized* group the book tree adds does not count. The page content
itself is gated on the server by the `/meta/doc` and `/meta/book/:name/tree`
reads. `visible` and `requiredPermissions` still apply and can only narrow
further.

`os build`, `os validate` and `os lint` refuse a `doc` item whose `book` or `doc`
names nothing in the package (rule `docs/nav-target`) — checked in the docs step,
Expand Down
Loading
Loading