Mount read-only inspector screens
Some bundled features ship read-only inspector screens over their internal read-models: a list (and detail) view an operator can open to see what is going on — GDPR export jobs, invalid download attempts, and so on. The screens live in the feature; your app only opts in by navigating them. No per-app screen code, no custom queries.
How to mount
Section titled “How to mount”The screens are registered but inert — they appear nowhere until your app navs
them. Add one r.nav per screen in any of your app features. They are
SystemAdmin-gated, so they surface only for platform operators:
defineFeature("my-app", (r) => { r.requires("user-data-rights");
r.nav({ id: "gdpr-export-jobs", label: "GDPR · Export Jobs", // qualified screen name: <feature>:screen:<id> screen: "user-data-rights:screen:export-job-list", access: { roles: ["SystemAdmin"] }, order: 90, });});That is the entire wiring. The list, the detail and their query handlers all
live in the feature — your app references the screen by its qualified name. The
nav resolves cross-feature with no import or coupling, and validateBoot fails
loudly if the screen name is wrong.
Which features ship inspector screens
Section titled “Which features ship inspector screens”| Feature | Screens | Shows | Gating |
|---|---|---|---|
user-data-rights | export-job-list, export-job-detail, download-attempt-list | GDPR Art. 20 export requests (user, status, requested / completed, expires) and invalid download attempts (result, IP, attempt time) — DPO brute-force triage | SystemAdmin |
This table grows as more features expose inspector screens.
Inspector screens use the entityList / entityEdit machinery, which binds to
an event-sourced r.entity read-model (rebuild-safe). Features whose read-model
is a direct-write store (jobs, sessions, billing-foundation) cannot use
this pattern — registering those as entities would wipe the live table on the
next projection rebuild. A separate query-bound read-only primitive for those is
tracked as a follow-up.